diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/agents/nepomukfeeder/nepomukfeederagentbase.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/agents/nepomukfeeder/nepomukfeederagentbase.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/agents/nepomukfeeder/nepomukfeederagentbase.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/agents/nepomukfeeder/nepomukfeederagentbase.cpp 2009-10-09 23:31:03.000000000 +0100 @@ -60,6 +60,14 @@ using namespace Akonadi; +static inline bool entityIsHidden( const Entity &entity ) +{ + EntityDisplayAttribute* attr = entity.attribute(); + if ( attr && attr->isHidden() ) + return true; + return false; +} + NepomukFeederAgentBase::NepomukFeederAgentBase(const QString& id) : AgentBase(id), mTotalAmount( 0 ), @@ -96,13 +104,16 @@ void NepomukFeederAgentBase::itemAdded(const Akonadi::Item& item, const Akonadi::Collection& collection) { - Q_UNUSED( collection ); + if ( entityIsHidden( collection ) ) + return; if ( item.hasPayload() ) updateItem( item, createGraphForEntity( item ) ); } void NepomukFeederAgentBase::itemChanged(const Akonadi::Item& item, const QSet< QByteArray >& partIdentifiers) { + if ( entityIsHidden( item.parentCollection() ) ) + return; // TODO: check part identfiers if anything interesting changed at all if ( item.hasPayload() ) { removeEntityFromNepomuk( item ); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/agents/nepomukfeeder/nepomukfeederagent.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/agents/nepomukfeeder/nepomukfeederagent.h --- kde-nightly-kdepim-20091006+svn1032120/akonadi/agents/nepomukfeeder/nepomukfeederagent.h 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/agents/nepomukfeeder/nepomukfeederagent.h 2009-10-09 23:31:03.000000000 +0100 @@ -39,6 +39,8 @@ { CollectionResource r( collection.url(), graphUri ); Akonadi::EntityDisplayAttribute *attr = collection.attribute(); + if ( attr && attr->isHidden() ) + return; if ( attr && !attr->displayName().isEmpty() ) r.setLabel( attr->displayName() ); else diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/akonadi_next/amazingdelegate.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/akonadi_next/amazingdelegate.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/akonadi_next/amazingdelegate.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/akonadi_next/amazingdelegate.cpp 2009-10-09 23:31:03.000000000 +0100 @@ -61,7 +61,7 @@ Collection parentCollection = index.data(EntityTreeModel::ParentCollectionRole).value(); - QString name = addressee.givenName() + ' ' + addressee.familyName(); + QString name = addressee.givenName() + QLatin1Char( ' ' ) + addressee.familyName(); KABC::Picture pic =addressee.photo(); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/akonadi_next/contactsmodel.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/akonadi_next/contactsmodel.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/akonadi_next/contactsmodel.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/akonadi_next/contactsmodel.cpp 2009-10-09 23:31:03.000000000 +0100 @@ -33,8 +33,8 @@ ContactsModelPrivate(ContactsModel *model) : q_ptr(model) { - m_collectionHeaders << "Collection" << "Count"; - m_itemHeaders << "Given Name" << "Family Name" << "Email"; + m_collectionHeaders << QLatin1String( "Collection" ) << QLatin1String( "Count" ); + m_itemHeaders << QLatin1String( "Given Name" ) << QLatin1String( "Family Name" ) << QLatin1String( "Email" ); } Q_DECLARE_PUBLIC(ContactsModel) @@ -102,7 +102,7 @@ QVariant ContactsModel::getData(const Item &item, int column, int role) const { - if ( item.mimeType() == "text/directory" ) + if ( item.mimeType() == QLatin1String( "text/directory" ) ) { if ( !item.hasPayload() ) { @@ -123,8 +123,6 @@ return addr.familyName(); case 2: return addr.preferredEmail(); - case 3: - return addr.givenName() + ' ' + addr.familyName() + ' ' + '<' + addr.preferredEmail() + '>'; } } } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/akonadi_next/mailmodel.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/akonadi_next/mailmodel.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/akonadi_next/mailmodel.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/akonadi_next/mailmodel.cpp 2009-10-09 23:31:03.000000000 +0100 @@ -37,8 +37,8 @@ MailModelPrivate(MailModel *model) : q_ptr(model) { - m_collectionHeaders << "Folder" << "Count"; - m_itemHeaders << "Subject" << "From" << "Date"; + m_collectionHeaders << QLatin1String( "Folder" ) << QLatin1String( "Count" ); + m_itemHeaders << QLatin1String( "Subject" ) << QLatin1String( "From" ) << QLatin1String( "Date" ); } Q_DECLARE_PUBLIC(MailModel) MailModel *q_ptr; @@ -81,9 +81,9 @@ } else if (role == Qt::ToolTipRole) { QString d; - d.append(QString("Subject: %1\n").arg(mail->subject()->asUnicodeString())); - d.append(QString("From: %1\n").arg(mail->from()->asUnicodeString())); - d.append(QString("Date: %1\n").arg(mail->date()->asUnicodeString())); + d.append(QString::fromLatin1("Subject: %1\n").arg(mail->subject()->asUnicodeString())); + d.append(QString::fromLatin1("From: %1\n").arg(mail->from()->asUnicodeString())); + d.append(QString::fromLatin1("Date: %1\n").arg(mail->date()->asUnicodeString())); return d; } return EntityTreeModel::getData(item, column, role); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/akonaditabbar.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/akonaditabbar.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/akonaditabbar.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/akonaditabbar.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,94 +0,0 @@ -/* - Copyright (C) 2009 Omat Holding B.V. - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include "akonaditabbar.h" -#include - -#include -#include -#include -#include - -using namespace Akonadi; - -class AkonadiTabBar::Private -{ -public: - Private( AkonadiTabBar* parent ); - QHash tabs; - AkonadiTabBar* q; - -public slots: - void slotCurrentChanged( int ); -}; - -AkonadiTabBar::Private::Private( AkonadiTabBar* parent ) : q( parent ) -{ -} - -void AkonadiTabBar::Private::slotCurrentChanged( int index ) -{ - q->emit currentChanged( tabs.value( index ) ); -} - -AkonadiTabBar::AkonadiTabBar( QWidget* parent ) - : KTabBar( parent ), d( new Private( this ) ) -{ - connect( this, SIGNAL( currentChanged( int ) ), - SLOT( slotCurrentChanged( int ) ) ); -} - -AkonadiTabBar::~AkonadiTabBar() -{ - delete d; -} - -void AkonadiTabBar::setResource( const QString &resource ) -{ - // save it for later. - int pastIndex = currentIndex(); - - // remote old tabs. - while ( count() > 0 ) - removeTab( 0 ); - d->tabs.clear(); - - // fetching all collections recursive, starting at the root collection - Collection col; - CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive ); - job->fetchScope().setResource( resource ); - if ( job->exec() ) { - Collection::List collections = job->collections(); - foreach( const Collection &collection, collections ) { - if ( collection.parentCollection() != Collection::root() ) { - int tab = addTab( collection.name() ); - d->tabs[ tab ] = collection; - } - } - } - - // setCurrent would not result in the emission of the signal, as that is already the current one. - if ( pastIndex <= 0 ) - emit currentChanged( d->tabs.value( 0 ) ); - else - setCurrentIndex( pastIndex ); -} - - -#include "akonaditabbar.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/akonaditabbar.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/akonaditabbar.h --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/akonaditabbar.h 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/akonaditabbar.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,78 +0,0 @@ -/* - Copyright (C) 2009 Omat Holding B.V. - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#ifndef __AKONADITABBAR_H__ -#define __AKONADITABBAR_H__ - -#include -#include - -/** - This class is a KTabBar which you can use to show your top level folders of - a resource. Call setResource() with your resource and it will create the tabs - automatically. Whenever a click is made on a tab, it will emit a signal with - the Collection. - - Example: - @code - - m_tabBar = new AkonadiTabBar( box ); - connect( m_tabBar, SIGNAL( currentChanged( const Akonadi::Collection& ) ), - SLOT( slotCurrentTabChanged( const Akonadi::Collection& ) ) ); - - # and in some slot something like: - const Akonadi::AgentInstanceModel *model = static_cast( view->model() ); - const QString identifier = model->data( index, AgentInstanceModel::InstanceIdentifierRole ).toString(); - m_tabBar->setResource( identifier ); - - @endcode - @author Tom Albers - @since 4.3 -*/ -class AkonadiTabBar : public KTabBar -{ - Q_OBJECT - -public: - /** Constructor */ - AkonadiTabBar( QWidget* parent ); - /** Destructor */ - ~AkonadiTabBar(); - /** - * Set the resource identifier which you want to use. The current tabs are removed and the new - * top-level folders of that resource are added again. If the 4th tab was selected previously, this - * will be the one selected after the new tabs are created. In any case, the - * currentChanged( Akonadi::Collection ) will be emitted after this call. - */ - void setResource( const QString& ); - -signals: - /** - * Signal emitted synchronisly with the currentChanged( int ) signal of KTabBar. This signal will - * also be emitted in all cases when setResource() has been called - */ - void currentChanged( Akonadi::Collection ); - -private: - class Private; - Private* d; - Q_PRIVATE_SLOT( d, void slotCurrentChanged( int ) ) -}; - -#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/blogmodel.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/blogmodel.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/blogmodel.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/blogmodel.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,131 +0,0 @@ -/* - Copyright (c) 2006 Volker Krause - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include "blogmodel.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -using namespace Akonadi; -using namespace Microblog; - -class BlogModel::Private -{ -public: -}; - -BlogModel::BlogModel( QObject *parent ) : - ItemModel( parent ), - d( new Private() ) -{ - fetchScope().fetchFullPayload(); -} - -BlogModel::~BlogModel( ) -{ - delete d; -} - -int BlogModel::columnCount( const QModelIndex & parent ) const -{ - if ( !parent.isValid() ) - return 1; - - return 0; -} - -QVariant BlogModel::data( const QModelIndex & index, int role ) const -{ - if ( role != Qt::DisplayRole && role != Qt::EditRole && role < Qt::UserRole ) - return QVariant(); - - if ( !index.isValid() ) - return QVariant(); - - if ( index.row() >= rowCount() ) - return QVariant(); - - Item item = itemForIndex( index ); - if ( !item.hasPayload() ) - return QVariant(); - - StatusItem msg = item.payload(); - Collection col = collection(); - - if ( role == Qt::EditRole ) { - return msg.date(); - } - - if ( role == Qt::DisplayRole ) - return msg.id(); - - switch ( role ) { - case Date: - return msg.date().toString(); - case User: - if ( role == Qt::UserRole+1 ) { - if ( col.remoteId() == "home" || col.remoteId() == "replies" || - col.remoteId() == "favorites" ) - return msg.value( "user_-_screen_name" ); - else if ( col.remoteId() == "inbox" ) - return msg.value( "sender_screen_name" ); - else if ( col.remoteId() == "outbox" ) - return msg.value( "recipient_screen_name" ); - else - return QVariant(); - } - case Text: - return msg.text(); - case Picture: - if ( role == Qt::UserRole+3 ) { - if ( col.remoteId() == "home" || col.remoteId() == "replies" || - col.remoteId() == "favorites" ) - return msg.value( "user_-_profile_image_url" ); - else if ( col.remoteId() == "inbox" ) - return msg.value( "sender_-_profile_image_url" ); - else if ( col.remoteId() == "outbox" ) - return msg.value( "recipient_-_profile_image_url" ); - else - return QVariant(); - } - default: - return QVariant(); - } - - return ItemModel::data( index, role ); -} - -QVariant BlogModel::headerData( int section, Qt::Orientation orientation, int role ) const -{ - if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) { - return i18nc( "@title:column, item id", "Blogs by date" ); - } - return ItemModel::headerData( section, orientation, role ); -} - -#include "blogmodel.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/blogmodel.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/blogmodel.h --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/blogmodel.h 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/blogmodel.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,76 +0,0 @@ -/* - Copyright (c) 2006 Volker Krause - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#ifndef AKONADI_BLOGMODEL_H -#define AKONADI_BLOGMODEL_H - -#include -#include - -/** - A flat self-updating message model. -*/ -class BlogModel : public Akonadi::ItemModel -{ - Q_OBJECT - -public: - /** - Column types. - */ - enum Column { - Date = Qt::UserRole, /**< Date column. */ - User, /**< Usre column. */ - Text, /**< Textr column. */ - Picture /**< url to a profile picture column. */ - }; - - /** - Creates a new message model. - - @param parent The parent object. - */ - explicit BlogModel( QObject* parent = 0 ); - - /** - Deletes the message model. - */ - virtual ~BlogModel(); - - /** - Reimplemented from QAbstractItemModel. - */ - virtual int columnCount( const QModelIndex & parent = QModelIndex() ) const; - - /** - Reimplemented from QAbstractItemModel. - */ - virtual QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; - - /** - Reimplemented from QAbstractItemModel. - */ - virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; - -private: - class Private; - Private* const d; -}; - -#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/CMakeLists.txt 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,16 +0,0 @@ -set(akonablog_bin_SRCS - main.cpp - mainwidget.cpp - mainwindow.cpp - blogmodel.cpp - microblogdelegate.cpp - akonaditabbar.cpp -) - -kde4_add_app_icon(akonablog_bin_SRCS "${KDE4_ICON_DIR}/oxygen/*/apps/email.png") - -kde4_add_executable(akonablog_bin ${akonablog_bin_SRCS}) -set_target_properties(akonablog_bin PROPERTIES OUTPUT_NAME akonablog) - -target_link_libraries(akonablog_bin ${KDEPIMLIBS_AKONADI_LIBS} ${KDE4_KDEUI_LIBS} ${QT_QTWEBKIT_LIBRARY} ${KDEPIMLIBS_KPIMUTILS_LIBS} ${KDEPIMLIBS_MICROBLOG_LIBS}) - diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/main.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/main.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/main.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/main.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,36 +0,0 @@ -/* - This file is part of Akonadi. - - Copyright (c) 2007 Bruno Virlet - - 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) any later version. - - 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. -*/ - -#include -#include - -#include "mainwindow.h" - -int main( int argc, char **argv ) -{ - KCmdLineArgs::init( argc, argv, "akonablog", 0, ki18n( "Akonablog" ), "1.0" , ki18n( "The blog client Proof-Of-Concept for Akonadi" ) ); - KApplication app; - - MainWindow window; - window.show(); - - return app.exec(); -} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/mainwidget.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/mainwidget.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/mainwidget.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/mainwidget.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,106 +0,0 @@ -/* - Copyright (c) 2007 Bruno Virlet - Copyright (c) 2009 Omat Holding B.V. - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include "mainwidget.h" -#include "mainwindow.h" -#include "blogmodel.h" -#include "microblogdelegate.h" -#include "akonaditabbar.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace Akonadi; - -MainWidget::MainWidget( MainWindow * parent ) : - QWidget( parent ), mMainWindow( parent ) -{ - QVBoxLayout *layout = new QVBoxLayout( this ); - - QSplitter *splitter = new QSplitter( Qt::Vertical, this ); - layout->addWidget( splitter ); - - - // Accounts - Akonadi::AgentInstanceModel *model = new Akonadi::AgentInstanceModel( this ); - m_resourcesView = new QListView( splitter ); - m_resourcesView->setModel( model ); - connect( m_resourcesView, SIGNAL( clicked( const QModelIndex& ) ), - SLOT( slotCurrentResourceChanged( const QModelIndex& ) ) ); - splitter->addWidget( m_resourcesView ); - - // Filter the collection to only show the blogs - Akonadi::AgentFilterProxyModel* proxy = new Akonadi::AgentFilterProxyModel( this ); - proxy->addMimeTypeFilter( "application/x-vnd.kde.microblog" ); - proxy->setSourceModel( model ); - m_resourcesView->setModel( proxy ); - - // Bottom part - KVBox* box = new KVBox( splitter ); - - // Folders - m_tabBar = new AkonadiTabBar( box ); - connect( m_tabBar, SIGNAL( currentChanged( const Akonadi::Collection& ) ), - SLOT( slotCurrentTabChanged( const Akonadi::Collection& ) ) ); - - mMessageList = new QTreeView( box ); - mMessageList->setRootIsDecorated( false ); - mMessageList->setDragEnabled( false ); - mMessageList->setSelectionMode( QAbstractItemView::ExtendedSelection ); - mMessageList->setSortingEnabled( true ); - - MicroblogDelegate *delegate = new MicroblogDelegate( mMessageList, this ); - mMessageList->setItemDelegate( delegate ); - - mMessageModel = new BlogModel( this ); - - QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel( this ); - proxyModel->setSortRole( Qt::EditRole ); - proxyModel->setDynamicSortFilter( true ); - proxyModel->setSourceModel( mMessageModel ); - - mMessageList->setModel( proxyModel ); - splitter->addWidget( box ); - - splitter->setSizes( QList() << 30 << 470 ); -} - -void MainWidget::slotCurrentResourceChanged( const QModelIndex &index ) -{ - const Akonadi::AgentInstanceModel *model = static_cast( m_resourcesView->model() ); - const QString identifier = model->data( index, AgentInstanceModel::InstanceIdentifierRole ).toString(); - m_tabBar->setResource( identifier ); -} - -void MainWidget::slotCurrentTabChanged( const Akonadi::Collection& col ) -{ - mMessageModel->setCollection( col ); -} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/mainwidget.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/mainwidget.h --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/mainwidget.h 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/mainwidget.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,51 +0,0 @@ -/* - Copyright (c) 2007 Bruno Virlet - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#ifndef MAINWIDGET_H -#define MAINWIDGET_H - -#include "blogmodel.h" -#include - -class QTreeView; -class QListView; -class AkonadiTabBar; -class MainWindow; - -class MainWidget: public QWidget -{ - Q_OBJECT - -public: - MainWidget( MainWindow *parent = 0 ); - -private slots: - void slotCurrentResourceChanged( const QModelIndex& ); - void slotCurrentTabChanged( const Akonadi::Collection& ); - -private: - BlogModel *mMessageModel; - QTreeView *mMessageList; - QListView *m_resourcesView; - AkonadiTabBar *m_tabBar; - - MainWindow *mMainWindow; -}; - -#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/mainwindow.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/mainwindow.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/mainwindow.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/mainwindow.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,41 +0,0 @@ -/* - This file is part of Akonadi. - - Copyright (c) 2006 Tobias Koenig - - 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) any later version. - - 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. -*/ - -#include "mainwindow.h" -#include "mainwidget.h" - -#include - -#include - -MainWindow::MainWindow( QWidget *parent ) - : QMainWindow( parent ) -{ - /* - QToolBar *toolBar = new QToolBar( QLatin1String( "Main toolbar" ), this ); - toolBar->addAction( "New", this, SIGNAL( threadCollection() ) ); - addToolBar( toolBar ); - */ - - Akonadi::Control::start( this ); - setCentralWidget( new MainWidget( this ) ); - resize( 440, 500 ); -} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/mainwindow.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/mainwindow.h --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/mainwindow.h 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/mainwindow.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,38 +0,0 @@ -/* - This file is part of Akonadi. - - Copyright (c) 2006 Tobias Koenig - - 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) any later version. - - 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. -*/ - -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - MainWindow( QWidget *parent = 0 ); - -signals: - void threadCollection(); -}; - -#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/microblogdelegate.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/microblogdelegate.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/microblogdelegate.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/microblogdelegate.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,114 +0,0 @@ -/* - Copyright (c) 2009 Omat Holding B.V. - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include "microblogdelegate.h" - -#include -#include -#include - -#include -#include -#include - -#include "blogmodel.h" - -MicroblogDelegate::MicroblogDelegate( QAbstractItemView *itemView, QObject * parent ) - : KWidgetItemDelegate( itemView, parent ), m_parent( itemView ) -{ -} - -QList MicroblogDelegate::createItemWidgets() const -{ - QList list; - - QWebView * infoLabel = new QWebView(); - infoLabel->setBackgroundRole( QPalette::NoRole ); - connect( infoLabel, SIGNAL( linkClicked( const QUrl & ) ), SLOT( slotLinkClicked( const QUrl & ) ) ); - list << infoLabel; - return list; -} - -void MicroblogDelegate::updateItemWidgets( const QList widgets, - const QStyleOptionViewItem &option, - const QPersistentModelIndex &index ) const -{ - Q_UNUSED( option ); - if ( !index.isValid() ) { - return; - } - - const BlogModel* model = static_cast( index.model() ); - int row = index.row(); - - QWebView *edit = static_cast( widgets[0] ); - edit->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks ); - edit->move( 5, 5 ); - edit->resize( 400,200 ); - - QString text; - text.append( "" ); - text.append( "
getData( model, row, BlogModel::Picture ).toString() + "\">" + getData( model, row, BlogModel::Date ).toString() ); - text.append( "
" + getData( model, row, BlogModel::User ).toString() ); - text.append( "
" ); - text.append( "
" + getData( model, row, BlogModel::Text ).toString() ); - //kDebug() << text; - edit->setHtml( text ); -} - -void MicroblogDelegate::slotLinkClicked( const QUrl &url ) -{ - KToolInvocation::invokeBrowser( url.toString() ); -} - -QVariant MicroblogDelegate::getData( const BlogModel* model, int row, int data ) const -{ - return model->data( model->index( row, 0 ), data ); -} - -void MicroblogDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const -{ - painter->save(); - - if ( option.state & QStyle::State_Selected ) { - painter->fillRect( option.rect, option.palette.highlight() ); - } else { - painter->fillRect( option.rect, ( index.row() % 2 == 0 ? option.palette.base() : option.palette.alternateBase() ) ); - painter->setPen( QPen( option.palette.window().color() ) ); - painter->drawRect( option.rect ); - } - - if ( option.state & QStyle::State_Selected ) { - painter->setPen( QPen( option.palette.highlightedText().color() ) ); - } else { - painter->setPen( QPen( option.palette.text().color() ) ); - } - - painter->restore(); -} - - -QSize MicroblogDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const -{ - Q_UNUSED( option ); - Q_UNUSED( index ); - - return QSize( 410, 210 ); -} -#include "microblogdelegate.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/microblogdelegate.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/microblogdelegate.h --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonablog/microblogdelegate.h 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonablog/microblogdelegate.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,53 +0,0 @@ -/* - Copyright (c) 2009 Omat Holding B.V. - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include - -#ifndef MICROBLOGDELEGATE_H -#define MICROBLOGDELEGATE_H - -class BlogModel; - -class MicroblogDelegate : public KWidgetItemDelegate -{ - Q_OBJECT - -public: - MicroblogDelegate( QAbstractItemView *itemView, QObject * parent ); - - QList createItemWidgets() const; - - void updateItemWidgets( const QList widgets, - const QStyleOptionViewItem &option, - const QPersistentModelIndex &index ) const; - - void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const; - QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const; - - -private slots: - void slotLinkClicked( const QUrl &url ); - -private: - QVariant getData( const BlogModel*, int row, int column ) const; - QWidget* m_parent; -}; - -#endif - diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/CMakeLists.txt 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,16 +0,0 @@ -include_directories( ${kdepim-runtime_SOURCE_DIR} ) - -set(akonamail_bin_SRCS - main.cpp - mainwidget.cpp - mainwindow.cpp -) - -kde4_add_app_icon(akonamail_bin_SRCS "${KDE4_ICON_DIR}/oxygen/*/apps/email.png") - -kde4_add_executable(akonamail_bin ${akonamail_bin_SRCS}) -set_target_properties(akonamail_bin PROPERTIES OUTPUT_NAME akonamail) - -target_link_libraries( akonamail_bin ${KDEPIMLIBS_AKONADI_LIBS} ${KDEPIMLIBS_AKONADI_KMIME_LIBS} ${KDE4_KDEUI_LIBS} ) - -#install(TARGETS akonamail_bin ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/main.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/main.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/main.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/main.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,36 +0,0 @@ -/* - This file is part of Akonadi. - - Copyright (c) 2007 Bruno Virlet - - 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) any later version. - - 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. -*/ - -#include -#include - -#include "mainwindow.h" - -int main( int argc, char **argv ) -{ - KCmdLineArgs::init( argc, argv, "akonamail", 0, ki18n("Akonamail"), "1.0" , ki18n("The mail client Proof-Of-Concept for Akonadi")); - KApplication app; - - MainWindow window; - window.show(); - - return app.exec(); -} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/mainwidget.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/mainwidget.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/mainwidget.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/mainwidget.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,138 +0,0 @@ -/* - Copyright (c) 2007 Bruno Virlet - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include "mainwidget.h" -#include "mainwindow.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace Akonadi; - -MainWidget::MainWidget( MainWindow * parent) : - QWidget( parent ), mMainWindow( parent ) -{ - connect( mMainWindow, SIGNAL( threadCollection() ), - this, SLOT( threadCollection() ) ); - - QHBoxLayout *layout = new QHBoxLayout( this ); - - QSplitter *splitter = new QSplitter( Qt::Horizontal, this ); - layout->addWidget( splitter ); - - // Left part, collection view - mCollectionList = new Akonadi::CollectionView(); - connect( mCollectionList, SIGNAL(clicked(const Akonadi::Collection &)), - SLOT(collectionClicked(const Akonadi::Collection &)) ); - CollectionStatisticsDelegate *collectionDelegate = - new CollectionStatisticsDelegate( mCollectionList ); - collectionDelegate->setUnreadCountShown( true ); //For testing, should be toggleable columns eventually - mCollectionList->setItemDelegate( collectionDelegate ); - splitter->addWidget( mCollectionList ); - // Filter the collection to only show the emails - mCollectionModel = new Akonadi::CollectionStatisticsModel( this ); - mCollectionProxyModel = new Akonadi::CollectionFilterProxyModel( this ); - mCollectionProxyModel->setSourceModel( mCollectionModel ); - mCollectionProxyModel->addMimeTypeFilter( QString::fromLatin1( "message/rfc822" ) ); - - // display collections sorted - QSortFilterProxyModel *sortModel = new QSortFilterProxyModel( this ); - sortModel->setDynamicSortFilter( true ); - sortModel->setSortCaseSensitivity( Qt::CaseInsensitive ); - sortModel->setSourceModel( mCollectionProxyModel ); - - // Right part, message list + message viewer - QSplitter *rightSplitter = new QSplitter( Qt::Vertical, this ); - splitter->addWidget( rightSplitter ); - mMessageList = new QTreeView( this ); - mMessageList->setDragEnabled( true ); - mMessageList->setSelectionMode( QAbstractItemView::ExtendedSelection ); - connect( mMessageList, SIGNAL(clicked(QModelIndex)), SLOT(itemActivated(QModelIndex)) ); - rightSplitter->addWidget( mMessageList ); - - mCollectionList->setModel( sortModel ); - mMessageModel = new Akonadi::MessageModel( this ); - mMessageProxyModel = new Akonadi::MessageThreaderProxyModel( this ); - mMessageProxyModel->setSourceModel( mMessageModel ); - mMessageList->setModel( mMessageProxyModel ); - - mMessageView = new QTextEdit( this ); - rightSplitter->addWidget( mMessageView ); - - - splitter->setSizes( QList() << 200 << 500 ); - rightSplitter->setSizes( QList() << 300 << 200 ); -} - -void MainWidget::collectionClicked(const Akonadi::Collection & collection) -{ - mCurrentCollection = collection; - mMessageModel->setCollection( Collection( mCurrentCollection ) ); -} - -void MainWidget::itemActivated(const QModelIndex & index) -{ - const Item item = mMessageModel->itemForIndex( mMessageProxyModel->mapToSource( index ) ); - - if ( !item.isValid() ) - return; - - ItemFetchJob *job = new ItemFetchJob( item, this ); - job->fetchScope().fetchFullPayload(); - connect( job, SIGNAL( result(KJob*) ), SLOT( itemFetchDone(KJob*) ) ); - job->start(); -} - -void MainWidget::itemFetchDone(KJob * job) -{ - ItemFetchJob *fetch = static_cast( job ); - if ( job->error() ) { - qWarning() << "Mail fetch failed: " << job->errorString(); - } else if ( fetch->items().isEmpty() ) { - qWarning() << "No mail found!"; - } else { - const Item item = fetch->items().first(); - mMessageView->setPlainText( item.payloadData() ); - } -} - -void MainWidget::threadCollection() -{ - /*MailThreaderAttribute *a = mCurrentCollection.attribute( Collection::AddIfMissing ); - a->deserialize( QByteArray( "sort" ) ); - CollectionModifyJob *job = new CollectionModifyJob( mCurrentCollection ); - if ( !job->exec() ) - qDebug() << "Unable to modify collection";*/ -} - - diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/mainwidget.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/mainwidget.h --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/mainwidget.h 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/mainwidget.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,69 +0,0 @@ -/* - Copyright (c) 2007 Bruno Virlet - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library 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 Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#ifndef MAINWIDGET_H -#define MAINWIDGET_H - -#include -#include - -class QModelIndex; -class QTreeView; -class QTextEdit; -class QSortFilterProxyModel; - -class KJob; - -namespace Akonadi { -class CollectionView; -class CollectionStatisticsModel; -class CollectionFilterProxyModel; -class MessageThreaderProxyModel; -class MessageModel; -} - -class MainWindow; - -class MainWidget: public QWidget -{ - Q_OBJECT - - public: - MainWidget( MainWindow *parent = 0 ); - - private slots: - void collectionClicked(const Akonadi::Collection & collection); - void itemActivated(const QModelIndex & index); - void itemFetchDone(KJob * job); - void threadCollection(); - - private: - Akonadi::Collection mCurrentCollection; - Akonadi::CollectionStatisticsModel *mCollectionModel; - Akonadi::CollectionFilterProxyModel *mCollectionProxyModel; - Akonadi::CollectionView *mCollectionList; - Akonadi::MessageModel *mMessageModel; - Akonadi::MessageThreaderProxyModel *mMessageProxyModel; - QTreeView *mMessageList; - QTextEdit *mMessageView; - - MainWindow *mMainWindow; -}; - -#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/mainwindow.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/mainwindow.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/mainwindow.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/mainwindow.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,39 +0,0 @@ -/* - This file is part of Akonadi. - - Copyright (c) 2006 Tobias Koenig - - 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) any later version. - - 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. -*/ - -#include "mainwindow.h" -#include "mainwidget.h" - -#include - -#include - -MainWindow::MainWindow( QWidget *parent ) - : QMainWindow( parent ) -{ - QToolBar *toolBar = new QToolBar( QLatin1String( "Main toolbar" ), this ); - toolBar->addAction( "Rethread", this, SIGNAL( threadCollection() ) ); - addToolBar( toolBar ); - - Akonadi::Control::start( this ); - setCentralWidget( new MainWidget( this ) ); - resize( 700, 500 ); -} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/mainwindow.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/mainwindow.h --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/akonamail/mainwindow.h 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/akonamail/mainwindow.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,38 +0,0 @@ -/* - This file is part of Akonadi. - - Copyright (c) 2006 Tobias Koenig - - 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) any later version. - - 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. -*/ - -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include - -class MainWindow : public QMainWindow -{ - Q_OBJECT - - public: - MainWindow( QWidget *parent = 0 ); - - signals: - void threadCollection(); -}; - -#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/akonadi/clients/CMakeLists.txt 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/clients/CMakeLists.txt 2009-10-09 23:31:06.000000000 +0100 @@ -1,4 +1,2 @@ add_subdirectory(kabc) -add_subdirectory(akonamail) add_subdirectory(akonalendar) -add_subdirectory(akonablog) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/kolabproxy/kolabproxyresource.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/kolabproxy/kolabproxyresource.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/kolabproxy/kolabproxyresource.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/kolabproxy/kolabproxyresource.cpp 2009-10-09 23:31:05.000000000 +0100 @@ -443,7 +443,8 @@ return; } //TODO: slow, would be nice if ItemCreateJob would work with a Collection having only the remoteId set - CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive ); + const Collection kolabCol = imapToKolab( collection ); + CollectionFetchJob *job = new CollectionFetchJob( kolabCol, CollectionFetchJob::Base, this ); connect(job, SIGNAL(result(KJob*)), this, SLOT(collectionFetchDone(KJob *))); m_ids[job] = QString::number(collection.id()); m_items[job] = item; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child1/cur/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child1/cur/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child1/cur/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child1/cur/.svn/entries 2009-10-09 23:31:05.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/child1/cur svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child1/new/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child1/new/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child1/new/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child1/new/.svn/entries 2009-10-09 23:31:05.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/child1/new svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child1/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child1/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child1/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child1/.svn/entries 2009-10-09 23:31:05.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/child1 svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child1/tmp/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child1/tmp/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child1/tmp/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child1/tmp/.svn/entries 2009-10-09 23:31:05.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/child1/tmp svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/cur/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/cur/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/cur/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/cur/.svn/entries 2009-10-09 23:31:04.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/cur svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/new/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/new/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/new/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/new/.svn/entries 2009-10-09 23:31:04.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/new svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/.svn/entries 2009-10-09 23:31:04.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/tmp/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/tmp/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/tmp/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/tmp/.svn/entries 2009-10-09 23:31:04.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/grandchild/tmp svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory/.svn/entries 2009-10-09 23:31:04.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/.child1.directory svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child2/cur/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child2/cur/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child2/cur/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child2/cur/.svn/entries 2009-10-09 23:31:05.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/child2/cur svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child2/new/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child2/new/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child2/new/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child2/new/.svn/entries 2009-10-09 23:31:05.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/child2/new svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child2/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child2/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child2/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child2/.svn/entries 2009-10-09 23:31:05.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/child2 svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child2/tmp/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child2/tmp/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/child2/tmp/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/child2/tmp/.svn/entries 2009-10-09 23:31:05.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory/child2/tmp svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.svn/entries /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.svn/entries --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/maildir/tests/maildir/.root.directory/.svn/entries 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/maildir/tests/maildir/.root.directory/.svn/entries 2009-10-09 23:31:04.000000000 +0100 @@ -1,7 +1,7 @@ 9 dir -1032120 +1033340 svn+ssh://sitter@svn.kde.org/home/kde/trunk/KDE/kdepim/akonadi/resources/maildir/tests/maildir/.root.directory svn+ssh://sitter@svn.kde.org/home/kde diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/openchange/howto.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/openchange/howto.txt --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/openchange/howto.txt 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/openchange/howto.txt 2009-10-09 23:31:06.000000000 +0100 @@ -1,3 +1 @@ - Get and install OpenChange's libmapi (http://www.openchange.org) -- Get and install libmapi++ (svn co https://svn.openchange.org/openchange/branches/libmapi++ && sudo mkdir /usr/local/samba/include/libmapi++ && sudo make install) - *** Note that right now libmapi++ make file assumes samba4 and OpenChange's libmapi are installed in /usr/local/samba *** diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/openchange/ocresource.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/openchange/ocresource.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/openchange/ocresource.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/openchange/ocresource.cpp 2009-10-09 23:31:06.000000000 +0100 @@ -20,7 +20,10 @@ 02110-1301, USA. */ -#include // for debugging +#include // for debugging +#include // for access() +#include // for getenv() +#include // fir mkdir() #include @@ -73,7 +76,7 @@ } #endif -typedef boost::shared_ptr MessagePtr; +typedef boost::shared_ptr MessagePtr; typedef boost::shared_ptr IncidencePtr; using namespace Akonadi; @@ -81,12 +84,34 @@ using KMime::Content; OCResource::OCResource( const QString &id ) - : ResourceBase( id ) + : ResourceBase( id ), m_session(NULL) { + // Assume we're using default location for profile database + std::string db_default_path = getenv("HOME"); + db_default_path += "/.openchange"; + + // Check if database exists + if (access(db_default_path.c_str(), F_OK) != 0) { + qDebug() << "OpenChange MAPI Profile database doesn't exist... creating one"; + mkdir(db_default_path.c_str(), 0700); + db_default_path += "profile.ldb"; + libmapipp::profile::create_profile_store(db_default_path.c_str(), "/usr/local/samba/share/setup"); // Assume samba4 is at /usr/local/sanba for now + qDebug() << "Successfully created OpenChange database!"; + } + + try { + m_session = new libmapipp::session; + qDebug() << "Successfully created MAPI Session"; + } catch (mapi_exception e) { + delete m_session; + qDebug() << "MAPI EXception: " << e.what(); + emit error(e.what()); + } } OCResource::~OCResource() { + if (m_session != NULL) delete m_session; } bool OCResource::retrieveItem( const Akonadi::Item &item, const QSet &parts ) @@ -99,7 +124,7 @@ libmapipp::message* messagePointer = NULL; try { - messagePointer = new libmapipp::message(m_session, folder_id, message_id); + messagePointer = new libmapipp::message(*m_session, folder_id, message_id); } catch (mapi_exception e) { cancelTask(e.what()); @@ -173,7 +198,7 @@ mapi_id_t message_id = ids[0].toULongLong(); mapi_id_t folder_id = ids[1].toULongLong(); - folder aFolder(m_session.get_message_store(), folder_id); + folder aFolder(m_session->get_message_store(), folder_id); aFolder.delete_message(message_id); @@ -240,7 +265,7 @@ { try { // TODO: handle password (third argument) - m_session.login(); + m_session->login(); } catch(mapi_exception e) { @@ -257,7 +282,7 @@ Collection::List collections; - property_container storeProperties = m_session.get_message_store().get_property_container(); + property_container storeProperties = m_session->get_message_store().get_property_container(); try { /* Retrieve the mailbox folder name */ storeProperties << PR_DISPLAY_NAME; @@ -271,7 +296,7 @@ Collection account; account.setParent( Collection::root() ); - account.setRemoteId( m_session.get_profile_name().c_str() ); + account.setRemoteId( m_session->get_profile_name().c_str() ); account.setName( QString( (const char*) *(storeProperties.begin()) ) + QString( " (OpenChange)" ) ); QStringList mimeTypes; mimeTypes << "inode/directory"; @@ -281,7 +306,7 @@ folder* top_folder= NULL; try { /* Prepare the directory listing */ - message_store& store = m_session.get_message_store(); + message_store& store = m_session->get_message_store(); mapi_id_t topFolderId = store.get_default_folder(olFolderTopInformationStore); top_folder = new folder(store, topFolderId); } @@ -328,8 +353,8 @@ struct SPropTagArray* flagList = NULL; SRowSet* rowSet = NULL; const char* usernames[2] = { username, NULL }; - if (ResolveNames(m_session.get_mapi_session(), usernames, tagArray, &rowSet, &flagList, 0) != MAPI_E_SUCCESS) { - if (ResolveNames(m_session.get_mapi_session(), usernames, tagArray, &rowSet, &flagList, MAPI_UNICODE) != MAPI_E_SUCCESS) { + if (ResolveNames(m_session->get_mapi_session(), usernames, tagArray, &rowSet, &flagList, 0) != MAPI_E_SUCCESS) { + if (ResolveNames(m_session->get_mapi_session(), usernames, tagArray, &rowSet, &flagList, MAPI_UNICODE) != MAPI_E_SUCCESS) { qDebug() << "*** COULD NOT RESOLVE EXCHANGE EMAIL ADDRESS ***"; } } @@ -1253,7 +1278,7 @@ } else { mapi_object_t objStream; mapi_object_init(&objStream); - OpenStream(&mapi_message.data(), PR_BODY, 0, &objStream); + OpenStream(&mapi_message.data(), PR_BODY, OpenStream_ReadOnly, &objStream); uint32_t dataSize; GetStreamSize(&objStream, &dataSize); @@ -1504,7 +1529,7 @@ } else { mapi_object_t objStream; mapi_object_init(&objStream); - OpenStream(&mapi_message.data(), PR_BODY, 0, &objStream); + OpenStream(&mapi_message.data(), PR_BODY, OpenStream_ReadOnly, &objStream); uint32_t dataSize; GetStreamSize(&objStream, &dataSize); @@ -1575,7 +1600,7 @@ folder::message_container_type* messages = NULL; QString contentType; try { - folderPtr = new folder(m_session.get_message_store(), collection.remoteId().toULongLong()); + folderPtr = new folder(m_session->get_message_store(), collection.remoteId().toULongLong()); messages = new folder::message_container_type(folderPtr->fetch_messages()); property_container folderProperties = folderPtr->get_property_container(); folderProperties << PR_CONTAINER_CLASS; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/openchange/ocresource.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/openchange/ocresource.h --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/openchange/ocresource.h 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/openchange/ocresource.h 2009-10-09 23:31:06.000000000 +0100 @@ -66,7 +66,7 @@ const Akonadi::Collection &parentCollection, Akonadi::Collection::List &collections); - libmapipp::session m_session; + libmapipp::session* m_session; QString m_profileDatabase; // TODO: maybe this should be a constructor arg? friend class ProfileDialog; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/openchange/profileeditdialog.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/openchange/profileeditdialog.cpp --- kde-nightly-kdepim-20091006+svn1032120/akonadi/resources/openchange/profileeditdialog.cpp 2009-10-06 23:28:09.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/akonadi/resources/openchange/profileeditdialog.cpp 2009-10-09 23:31:06.000000000 +0100 @@ -186,7 +186,7 @@ mapi_profile_add_string_attr(m_profileNameEdit->text().toUtf8().constData(), "codepage", "0x4e4"); mapi_profile_add_string_attr(m_profileNameEdit->text().toUtf8().constData(), - "language", "0x40c"); + "language", "0x409"); // default to en-US for now TODO: create an option for this mapi_profile_add_string_attr(m_profileNameEdit->text().toUtf8().constData(), "method", "0x409"); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/blogilo/blogilo.desktop /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/blogilo/blogilo.desktop --- kde-nightly-kdepim-20091006+svn1032120/blogilo/blogilo.desktop 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/blogilo/blogilo.desktop 2009-10-09 23:31:07.000000000 +0100 @@ -1,5 +1,6 @@ [Desktop Entry] Name=Blogilo +Name[gl]=Blogilo Name[nds]=Blogilo Name[pt]=Blogilo Name[pt_BR]=Blogilo @@ -11,6 +12,7 @@ Type=Application Categories=Qt;KDE;Network; GenericName=A KDE Blogging Client +GenericName[gl]=Un cliente para blogues de KDE GenericName[nds]=En Nettdaagbook-Programm för KDE GenericName[pt]=Um Cliente de Blogs para o KDE GenericName[pt_BR]=Um cliente de blog do KDE diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/bilboeditor.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/bilboeditor.cpp --- kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/bilboeditor.cpp 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/bilboeditor.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -127,7 +127,11 @@ connect( editor, SIGNAL( checkSpellingChanged( bool ) ), this, SLOT( sltSyncSpellCheckingButton( bool ) ) ); - connect( editor, SIGNAL( cursorPositionChanged() ), this, SLOT( sltSyncToolbar() ) ); + connect( editor, SIGNAL(currentBlockFormatChanged(QTextBlockFormat)), + this, SLOT(slotCurrentBlockFormatChanged(QTextBlockFormat)) ); + connect( editor, SIGNAL(currentCharFormatChanged(QTextCharFormat)), + this, SLOT(slotCurrentCharFormantChanged(QTextCharFormat)) ); +// connect( editor, SIGNAL( cursorPositionChanged() ), this, SLOT( sltSyncToolbar() ) ); ///htmlEditor: htmlEditor = HtmlEditor::self()->createView( tabHtml ); @@ -667,36 +671,6 @@ editor->document()->setUndoRedoEnabled( true ); } -// void BilboEditor::sltAddMedia() -// { -// AddMediaDialog *mediaDialog = new AddMediaDialog( this ); -// // mediaDialog->setAttribute( Qt::WA_DeleteOnClose ); -// mediaDialog->setWindowModality( Qt::WindowModal ); -// -// connect( mediaDialog, SIGNAL( sigAddMedia( BilboMedia * ) ), this, SLOT( sltSetMedia( BilboMedia * ) ) ); -// connect( mediaDialog, SIGNAL( sigMediaTypeFound( BilboMedia * ) ), this, -// SLOT( sltMediaTypeFound( BilboMedia * ) ) ); -// mediaDialog->exec(); -// mediaDialog->deleteLater(); -// } - -// void BilboEditor::sltSetMedia( BilboMedia *media ) -// { -// QTextCharFormat f; -// QString url = media->remoteUrl().url(); -// -// f.setAnchor( true ); -// f.setAnchorHref( url ); -// editor->textCursor().insertText( media->name(), f ); -// // editor->document()->addResource( QTextDocument::UserResource, -// // QUrl( url ), QVariant( url ) ); -// -// editor->document()->setUndoRedoEnabled( false ); -// editor->document()->setUndoRedoEnabled( true ); -// -// editor->setFocus( Qt::OtherFocusReason ); -// } - void BilboEditor::sltSetImageProperties( const int index, const int width, const int height, const QString title, const QString link, const QString Alt_text ) @@ -878,47 +852,40 @@ editor->textCursor().insertBlock( f1 ); } -void BilboEditor::sltSyncToolbar() +void BilboEditor::slotCurrentCharFormantChanged(const QTextCharFormat &charFormat) { - if ( this->editor->textCursor().charFormat() != lastCharFormat ) { - lastCharFormat = this->editor->textCursor().charFormat(); - - if ( lastCharFormat.fontWeight() == QFont::Bold ) { - this->actBold->setChecked( true ); - } else { - this->actBold->setChecked( false ); - } - this->actItalic->setChecked( lastCharFormat.fontItalic() ); - this->actUnderline->setChecked( lastCharFormat.fontUnderline() ); - this->actStrikeout->setChecked( lastCharFormat.fontStrikeOut() ); - if ( lastCharFormat.hasProperty( BilboTextFormat::HasCodeStyle ) && - lastCharFormat.boolProperty( BilboTextFormat::HasCodeStyle ) ) { - this->actCode->setChecked( true ); - } else { - this->actCode->setChecked( false ); - } + if ( charFormat.fontWeight() == QFont::Bold ) { + this->actBold->setChecked( true ); + } else { + this->actBold->setChecked( false ); } - if ( this->editor->textCursor().blockFormat() != lastBlockFormat ) { - lastBlockFormat = this->editor->textCursor().blockFormat(); - - if ( lastBlockFormat.layoutDirection() == Qt::RightToLeft ) { + this->actItalic->setChecked( charFormat.fontItalic() ); + this->actUnderline->setChecked( charFormat.fontUnderline() ); + this->actStrikeout->setChecked( charFormat.fontStrikeOut() ); + if ( charFormat.hasProperty( BilboTextFormat::HasCodeStyle ) && + charFormat.boolProperty( BilboTextFormat::HasCodeStyle ) ) { + this->actCode->setChecked( true ); + } else { + this->actCode->setChecked( false ); + } +} + +void BilboEditor::slotCurrentBlockFormatChanged(const QTextBlockFormat& blockFormat) +{ + if ( blockFormat.layoutDirection() == Qt::RightToLeft ) { this->actRightToLeft->setChecked( true ); } else { this->actRightToLeft->setChecked( false ); } - if ( !lastBlockFormat.hasProperty( BilboTextFormat::HtmlHeading ) ) { + if ( !blockFormat.hasProperty( BilboTextFormat::HtmlHeading ) ) { this->actFormatType->setCurrentItem( 0 ); } else { - this->actFormatType->setCurrentItem( lastBlockFormat.intProperty( + this->actFormatType->setCurrentItem( blockFormat.intProperty( BilboTextFormat::HtmlHeading ) ); } - if ( lastBlockFormat.hasProperty( BilboTextFormat::IsBlockQuote ) && - lastBlockFormat.boolProperty( BilboTextFormat::IsBlockQuote ) ) { - this->actBlockQuote->setChecked( true ); - } else { - this->actBlockQuote->setChecked( false ); + if ( blockFormat.hasProperty( BilboTextFormat::IsBlockQuote ) ){ + this->actBlockQuote->setChecked( blockFormat.boolProperty( BilboTextFormat::IsBlockQuote ) ); } - } } void BilboEditor::sltSyncEditors( int index ) @@ -966,19 +933,6 @@ // doc->deleteLater(); } -// QString BilboEditor::htmlToRichtext( const QString& html ) -// { -// QString richText = html; -// -// richText.remove( QChar( '\n' ) ); -// -// richText.replace( QRegExp( "(.*)" ), "\\1" ); -// -// QString h; -// h = "

" + richText + "

"; -// return h; -// } - QString BilboEditor::htmlContent() { if ( this->currentIndex() == 0 ) { diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/bilboeditor.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/bilboeditor.h --- kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/bilboeditor.h 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/bilboeditor.h 2009-10-09 23:31:07.000000000 +0100 @@ -245,9 +245,9 @@ * @param media is a BilboMedia object, which contains media path, mimetype and other needed information about it. */ // void sltSetMedia( BilboMedia *media ); - + void sltRemoveMedia( const int index ); - + void sltMediaTypeFound( BilboMedia *media ); void sltAddOrderedList(); @@ -258,7 +258,8 @@ void sltAddPostSplitter(); - void sltSyncToolbar(); + void slotCurrentCharFormantChanged(const QTextCharFormat &); + void slotCurrentBlockFormatChanged(const QTextBlockFormat &); /*! Sets the content of the current tab as other tabs' contents, to apply recent @@ -343,8 +344,8 @@ QTextCharFormat defaultCharFormat; QTextBlockFormat defaultBlockFormat; - QTextCharFormat lastCharFormat; - QTextBlockFormat lastBlockFormat; +// QTextCharFormat lastCharFormat; +// QTextBlockFormat lastBlockFormat; QMap *mMediaList; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/dialogs/addmediadialog.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/dialogs/addmediadialog.cpp --- kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/dialogs/addmediadialog.cpp 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/dialogs/addmediadialog.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -46,7 +46,7 @@ this->setMainWidget( dialog ); this->resize( dialog->width(), dialog->height() ); - this->setWindowTitle( "Attach media" ); + this->setWindowTitle( i18n("Attach media") ); connect( this, SIGNAL( okClicked() ), this, SLOT( sltOkClicked() ) ); connect( ui.radiobtnLocalUrl, SIGNAL( toggled( bool ) ), this, diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/multilinetextedit.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/multilinetextedit.cpp --- kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/multilinetextedit.cpp 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/multilinetextedit.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -39,11 +39,12 @@ #include QMap MultiLineTextEdit::downloadFinished; -MultiLineTextEdit::MultiLineTextEdit( QWidget *parent ) : KRichTextEdit( parent ) + +MultiLineTextEdit::MultiLineTextEdit( QWidget *parent ) + : KRichTextEdit( parent ) { -// netManager = new QNetworkAccessManager( this ); -// connect( manager, SIGNAL( finished( QNetworkReply* ) ), this, -// SLOT( sltReplyFinished( QNetworkReply* ) ) ); + connect( this, SIGNAL(cursorPositionChanged()), + this, SLOT(slotCursorPositionChanged()) ); } MultiLineTextEdit::~MultiLineTextEdit() @@ -179,5 +180,14 @@ mMediaList = list; } +void MultiLineTextEdit::slotCursorPositionChanged() +{ + QTextBlockFormat tmpBlock = textCursor().blockFormat(); + if( tmpBlock != lastBlockFormat){ + lastBlockFormat = tmpBlock; + emit currentBlockFormatChanged( tmpBlock ); + } +} + #include "composer/multilinetextedit.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/multilinetextedit.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/multilinetextedit.h --- kde-nightly-kdepim-20091006+svn1032120/blogilo/src/composer/multilinetextedit.h 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/blogilo/src/composer/multilinetextedit.h 2009-10-09 23:31:07.000000000 +0100 @@ -86,6 +86,11 @@ */ void sigMediaTypeFound( BilboMedia *media ); + /** + * Emitted when current Text Block format changed! + */ + void currentBlockFormatChanged(const QTextBlockFormat &); + protected: /*! @@ -107,31 +112,14 @@ */ virtual QVariant loadResource( int type, const QUrl & name ); -// private: -// QNetworkAccessManager *netManager; -// private Q_SLOTS: - void sltRemoteFileCopied(KJob * job); + void slotCursorPositionChanged(); private: static QMap downloadFinished; QMap *mMediaList; + QTextBlockFormat lastBlockFormat; }; -// class GetImageThread : public QThread -// { -// -// public: -// GetImageThread( KRichTextEdit *parent = 0, const KUrl & image); -// // ~GetImageThread(); -// -// protected: -// virtual void run(); -// -// private: -// KUrl imageUrl; -// QTextCursor cursor; -// }; - #endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/CMakeLists.txt 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/CMakeLists.txt 2009-10-09 23:30:59.000000000 +0100 @@ -173,6 +173,7 @@ add_subdirectory(mimelib) add_subdirectory(kdgantt1) add_subdirectory(icons) + add_subdirectory(messagecore) add_subdirectory(messagelist) if(QGPGME_FOUND) @@ -181,7 +182,9 @@ endif(Boost_TOPOLOGICAL_SORT_DIR) add_subdirectory(wizards) # The following components depend on QGpgME. + add_subdirectory(messageviewer) macro_optional_add_subdirectory(kmail) + macro_optional_add_subdirectory(examples) # If kmail is compiled, KMAIL_SUPPORTED is true (used in several places) if(BUILD_kmail) set(KMAIL_SUPPORTED TRUE) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/debian/changelog /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/debian/changelog --- kde-nightly-kdepim-20091006+svn1032120/debian/changelog 2009-10-07 05:14:47.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/debian/changelog 2009-10-10 08:05:23.000000000 +0100 @@ -1,8 +1,8 @@ -kde-nightly-kdepim (20091006+svn1032120-0neon1) jaunty; urgency=low +kde-nightly-kdepim (20091009+svn1033340-0neon1) jaunty; urgency=low * Nightly Build - -- Project Neon Wed, 07 Oct 2009 00:14:48 -0400 + -- Project Neon Sat, 10 Oct 2009 03:05:24 -0400 kde-nightly-kdepim (20080303-0amarok1) gutsy; urgency=low diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/akonaditabbar.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/akonaditabbar.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/akonaditabbar.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/akonaditabbar.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,94 @@ +/* + Copyright (C) 2009 Omat Holding B.V. + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "akonaditabbar.h" +#include + +#include +#include +#include +#include + +using namespace Akonadi; + +class AkonadiTabBar::Private +{ +public: + Private( AkonadiTabBar* parent ); + QHash tabs; + AkonadiTabBar* q; + +public slots: + void slotCurrentChanged( int ); +}; + +AkonadiTabBar::Private::Private( AkonadiTabBar* parent ) : q( parent ) +{ +} + +void AkonadiTabBar::Private::slotCurrentChanged( int index ) +{ + q->emit currentChanged( tabs.value( index ) ); +} + +AkonadiTabBar::AkonadiTabBar( QWidget* parent ) + : KTabBar( parent ), d( new Private( this ) ) +{ + connect( this, SIGNAL( currentChanged( int ) ), + SLOT( slotCurrentChanged( int ) ) ); +} + +AkonadiTabBar::~AkonadiTabBar() +{ + delete d; +} + +void AkonadiTabBar::setResource( const QString &resource ) +{ + // save it for later. + int pastIndex = currentIndex(); + + // remote old tabs. + while ( count() > 0 ) + removeTab( 0 ); + d->tabs.clear(); + + // fetching all collections recursive, starting at the root collection + Collection col; + CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive ); + job->fetchScope().setResource( resource ); + if ( job->exec() ) { + Collection::List collections = job->collections(); + foreach( const Collection &collection, collections ) { + if ( collection.parentCollection() != Collection::root() ) { + int tab = addTab( collection.name() ); + d->tabs[ tab ] = collection; + } + } + } + + // setCurrent would not result in the emission of the signal, as that is already the current one. + if ( pastIndex <= 0 ) + emit currentChanged( d->tabs.value( 0 ) ); + else + setCurrentIndex( pastIndex ); +} + + +#include "akonaditabbar.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/akonaditabbar.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/akonaditabbar.h --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/akonaditabbar.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/akonaditabbar.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,78 @@ +/* + Copyright (C) 2009 Omat Holding B.V. + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef __AKONADITABBAR_H__ +#define __AKONADITABBAR_H__ + +#include +#include + +/** + This class is a KTabBar which you can use to show your top level folders of + a resource. Call setResource() with your resource and it will create the tabs + automatically. Whenever a click is made on a tab, it will emit a signal with + the Collection. + + Example: + @code + + m_tabBar = new AkonadiTabBar( box ); + connect( m_tabBar, SIGNAL( currentChanged( const Akonadi::Collection& ) ), + SLOT( slotCurrentTabChanged( const Akonadi::Collection& ) ) ); + + # and in some slot something like: + const Akonadi::AgentInstanceModel *model = static_cast( view->model() ); + const QString identifier = model->data( index, AgentInstanceModel::InstanceIdentifierRole ).toString(); + m_tabBar->setResource( identifier ); + + @endcode + @author Tom Albers + @since 4.3 +*/ +class AkonadiTabBar : public KTabBar +{ + Q_OBJECT + +public: + /** Constructor */ + AkonadiTabBar( QWidget* parent ); + /** Destructor */ + ~AkonadiTabBar(); + /** + * Set the resource identifier which you want to use. The current tabs are removed and the new + * top-level folders of that resource are added again. If the 4th tab was selected previously, this + * will be the one selected after the new tabs are created. In any case, the + * currentChanged( Akonadi::Collection ) will be emitted after this call. + */ + void setResource( const QString& ); + +signals: + /** + * Signal emitted synchronisly with the currentChanged( int ) signal of KTabBar. This signal will + * also be emitted in all cases when setResource() has been called + */ + void currentChanged( Akonadi::Collection ); + +private: + class Private; + Private* d; + Q_PRIVATE_SLOT( d, void slotCurrentChanged( int ) ) +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/blogmodel.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/blogmodel.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/blogmodel.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/blogmodel.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,131 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "blogmodel.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace Akonadi; +using namespace Microblog; + +class BlogModel::Private +{ +public: +}; + +BlogModel::BlogModel( QObject *parent ) : + ItemModel( parent ), + d( new Private() ) +{ + fetchScope().fetchFullPayload(); +} + +BlogModel::~BlogModel( ) +{ + delete d; +} + +int BlogModel::columnCount( const QModelIndex & parent ) const +{ + if ( !parent.isValid() ) + return 1; + + return 0; +} + +QVariant BlogModel::data( const QModelIndex & index, int role ) const +{ + if ( role != Qt::DisplayRole && role != Qt::EditRole && role < Qt::UserRole ) + return QVariant(); + + if ( !index.isValid() ) + return QVariant(); + + if ( index.row() >= rowCount() ) + return QVariant(); + + Item item = itemForIndex( index ); + if ( !item.hasPayload() ) + return QVariant(); + + StatusItem msg = item.payload(); + Collection col = collection(); + + if ( role == Qt::EditRole ) { + return msg.date(); + } + + if ( role == Qt::DisplayRole ) + return msg.id(); + + switch ( role ) { + case Date: + return msg.date().toString(); + case User: + if ( role == Qt::UserRole+1 ) { + if ( col.remoteId() == "home" || col.remoteId() == "replies" || + col.remoteId() == "favorites" ) + return msg.value( "user_-_screen_name" ); + else if ( col.remoteId() == "inbox" ) + return msg.value( "sender_screen_name" ); + else if ( col.remoteId() == "outbox" ) + return msg.value( "recipient_screen_name" ); + else + return QVariant(); + } + case Text: + return msg.text(); + case Picture: + if ( role == Qt::UserRole+3 ) { + if ( col.remoteId() == "home" || col.remoteId() == "replies" || + col.remoteId() == "favorites" ) + return msg.value( "user_-_profile_image_url" ); + else if ( col.remoteId() == "inbox" ) + return msg.value( "sender_-_profile_image_url" ); + else if ( col.remoteId() == "outbox" ) + return msg.value( "recipient_-_profile_image_url" ); + else + return QVariant(); + } + default: + return QVariant(); + } + + return ItemModel::data( index, role ); +} + +QVariant BlogModel::headerData( int section, Qt::Orientation orientation, int role ) const +{ + if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) { + return i18nc( "@title:column, item id", "Blogs by date" ); + } + return ItemModel::headerData( section, orientation, role ); +} + +#include "blogmodel.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/blogmodel.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/blogmodel.h --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/blogmodel.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/blogmodel.h 2009-10-09 23:31:06.000000000 +0100 @@ -0,0 +1,76 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef AKONADI_BLOGMODEL_H +#define AKONADI_BLOGMODEL_H + +#include +#include + +/** + A flat self-updating message model. +*/ +class BlogModel : public Akonadi::ItemModel +{ + Q_OBJECT + +public: + /** + Column types. + */ + enum Column { + Date = Qt::UserRole, /**< Date column. */ + User, /**< Usre column. */ + Text, /**< Textr column. */ + Picture /**< url to a profile picture column. */ + }; + + /** + Creates a new message model. + + @param parent The parent object. + */ + explicit BlogModel( QObject* parent = 0 ); + + /** + Deletes the message model. + */ + virtual ~BlogModel(); + + /** + Reimplemented from QAbstractItemModel. + */ + virtual int columnCount( const QModelIndex & parent = QModelIndex() ) const; + + /** + Reimplemented from QAbstractItemModel. + */ + virtual QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; + + /** + Reimplemented from QAbstractItemModel. + */ + virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; + +private: + class Private; + Private* const d; +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/CMakeLists.txt 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,16 @@ +set(akonablog_bin_SRCS + main.cpp + mainwidget.cpp + mainwindow.cpp + blogmodel.cpp + microblogdelegate.cpp + akonaditabbar.cpp +) + +kde4_add_app_icon(akonablog_bin_SRCS "${KDE4_ICON_DIR}/oxygen/*/apps/email.png") + +kde4_add_executable(akonablog_bin ${akonablog_bin_SRCS}) +set_target_properties(akonablog_bin PROPERTIES OUTPUT_NAME akonablog) + +target_link_libraries(akonablog_bin ${KDEPIMLIBS_AKONADI_LIBS} ${KDE4_KDEUI_LIBS} ${QT_QTWEBKIT_LIBRARY} ${KDEPIMLIBS_KPIMUTILS_LIBS} ${KDEPIMLIBS_MICROBLOG_LIBS}) + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/main.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/main.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/main.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/main.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,36 @@ +/* + This file is part of Akonadi. + + Copyright (c) 2007 Bruno Virlet + + 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) any later version. + + 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. +*/ + +#include +#include + +#include "mainwindow.h" + +int main( int argc, char **argv ) +{ + KCmdLineArgs::init( argc, argv, "akonablog", 0, ki18n( "Akonablog" ), "1.0" , ki18n( "The blog client Proof-Of-Concept for Akonadi" ) ); + KApplication app; + + MainWindow window; + window.show(); + + return app.exec(); +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/mainwidget.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/mainwidget.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/mainwidget.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/mainwidget.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,106 @@ +/* + Copyright (c) 2007 Bruno Virlet + Copyright (c) 2009 Omat Holding B.V. + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "mainwidget.h" +#include "mainwindow.h" +#include "blogmodel.h" +#include "microblogdelegate.h" +#include "akonaditabbar.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace Akonadi; + +MainWidget::MainWidget( MainWindow * parent ) : + QWidget( parent ), mMainWindow( parent ) +{ + QVBoxLayout *layout = new QVBoxLayout( this ); + + QSplitter *splitter = new QSplitter( Qt::Vertical, this ); + layout->addWidget( splitter ); + + + // Accounts + Akonadi::AgentInstanceModel *model = new Akonadi::AgentInstanceModel( this ); + m_resourcesView = new QListView( splitter ); + m_resourcesView->setModel( model ); + connect( m_resourcesView, SIGNAL( clicked( const QModelIndex& ) ), + SLOT( slotCurrentResourceChanged( const QModelIndex& ) ) ); + splitter->addWidget( m_resourcesView ); + + // Filter the collection to only show the blogs + Akonadi::AgentFilterProxyModel* proxy = new Akonadi::AgentFilterProxyModel( this ); + proxy->addMimeTypeFilter( "application/x-vnd.kde.microblog" ); + proxy->setSourceModel( model ); + m_resourcesView->setModel( proxy ); + + // Bottom part + KVBox* box = new KVBox( splitter ); + + // Folders + m_tabBar = new AkonadiTabBar( box ); + connect( m_tabBar, SIGNAL( currentChanged( const Akonadi::Collection& ) ), + SLOT( slotCurrentTabChanged( const Akonadi::Collection& ) ) ); + + mMessageList = new QTreeView( box ); + mMessageList->setRootIsDecorated( false ); + mMessageList->setDragEnabled( false ); + mMessageList->setSelectionMode( QAbstractItemView::ExtendedSelection ); + mMessageList->setSortingEnabled( true ); + + MicroblogDelegate *delegate = new MicroblogDelegate( mMessageList, this ); + mMessageList->setItemDelegate( delegate ); + + mMessageModel = new BlogModel( this ); + + QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel( this ); + proxyModel->setSortRole( Qt::EditRole ); + proxyModel->setDynamicSortFilter( true ); + proxyModel->setSourceModel( mMessageModel ); + + mMessageList->setModel( proxyModel ); + splitter->addWidget( box ); + + splitter->setSizes( QList() << 30 << 470 ); +} + +void MainWidget::slotCurrentResourceChanged( const QModelIndex &index ) +{ + const Akonadi::AgentInstanceModel *model = static_cast( m_resourcesView->model() ); + const QString identifier = model->data( index, AgentInstanceModel::InstanceIdentifierRole ).toString(); + m_tabBar->setResource( identifier ); +} + +void MainWidget::slotCurrentTabChanged( const Akonadi::Collection& col ) +{ + mMessageModel->setCollection( col ); +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/mainwidget.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/mainwidget.h --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/mainwidget.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/mainwidget.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,51 @@ +/* + Copyright (c) 2007 Bruno Virlet + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef MAINWIDGET_H +#define MAINWIDGET_H + +#include "blogmodel.h" +#include + +class QTreeView; +class QListView; +class AkonadiTabBar; +class MainWindow; + +class MainWidget: public QWidget +{ + Q_OBJECT + +public: + MainWidget( MainWindow *parent = 0 ); + +private slots: + void slotCurrentResourceChanged( const QModelIndex& ); + void slotCurrentTabChanged( const Akonadi::Collection& ); + +private: + BlogModel *mMessageModel; + QTreeView *mMessageList; + QListView *m_resourcesView; + AkonadiTabBar *m_tabBar; + + MainWindow *mMainWindow; +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/mainwindow.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/mainwindow.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/mainwindow.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/mainwindow.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,41 @@ +/* + This file is part of Akonadi. + + Copyright (c) 2006 Tobias Koenig + + 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) any later version. + + 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. +*/ + +#include "mainwindow.h" +#include "mainwidget.h" + +#include + +#include + +MainWindow::MainWindow( QWidget *parent ) + : QMainWindow( parent ) +{ + /* + QToolBar *toolBar = new QToolBar( QLatin1String( "Main toolbar" ), this ); + toolBar->addAction( "New", this, SIGNAL( threadCollection() ) ); + addToolBar( toolBar ); + */ + + Akonadi::Control::start( this ); + setCentralWidget( new MainWidget( this ) ); + resize( 440, 500 ); +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/mainwindow.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/mainwindow.h --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/mainwindow.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/mainwindow.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,38 @@ +/* + This file is part of Akonadi. + + Copyright (c) 2006 Tobias Koenig + + 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) any later version. + + 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. +*/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow( QWidget *parent = 0 ); + +signals: + void threadCollection(); +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/microblogdelegate.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/microblogdelegate.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/microblogdelegate.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/microblogdelegate.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,114 @@ +/* + Copyright (c) 2009 Omat Holding B.V. + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "microblogdelegate.h" + +#include +#include +#include + +#include +#include +#include + +#include "blogmodel.h" + +MicroblogDelegate::MicroblogDelegate( QAbstractItemView *itemView, QObject * parent ) + : KWidgetItemDelegate( itemView, parent ), m_parent( itemView ) +{ +} + +QList MicroblogDelegate::createItemWidgets() const +{ + QList list; + + QWebView * infoLabel = new QWebView(); + infoLabel->setBackgroundRole( QPalette::NoRole ); + connect( infoLabel, SIGNAL( linkClicked( const QUrl & ) ), SLOT( slotLinkClicked( const QUrl & ) ) ); + list << infoLabel; + return list; +} + +void MicroblogDelegate::updateItemWidgets( const QList widgets, + const QStyleOptionViewItem &option, + const QPersistentModelIndex &index ) const +{ + Q_UNUSED( option ); + if ( !index.isValid() ) { + return; + } + + const BlogModel* model = static_cast( index.model() ); + int row = index.row(); + + QWebView *edit = static_cast( widgets[0] ); + edit->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks ); + edit->move( 5, 5 ); + edit->resize( 400,200 ); + + QString text; + text.append( "" ); + text.append( "
getData( model, row, BlogModel::Picture ).toString() + "\">" + getData( model, row, BlogModel::Date ).toString() ); + text.append( "
" + getData( model, row, BlogModel::User ).toString() ); + text.append( "
" ); + text.append( "
" + getData( model, row, BlogModel::Text ).toString() ); + //kDebug() << text; + edit->setHtml( text ); +} + +void MicroblogDelegate::slotLinkClicked( const QUrl &url ) +{ + KToolInvocation::invokeBrowser( url.toString() ); +} + +QVariant MicroblogDelegate::getData( const BlogModel* model, int row, int data ) const +{ + return model->data( model->index( row, 0 ), data ); +} + +void MicroblogDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const +{ + painter->save(); + + if ( option.state & QStyle::State_Selected ) { + painter->fillRect( option.rect, option.palette.highlight() ); + } else { + painter->fillRect( option.rect, ( index.row() % 2 == 0 ? option.palette.base() : option.palette.alternateBase() ) ); + painter->setPen( QPen( option.palette.window().color() ) ); + painter->drawRect( option.rect ); + } + + if ( option.state & QStyle::State_Selected ) { + painter->setPen( QPen( option.palette.highlightedText().color() ) ); + } else { + painter->setPen( QPen( option.palette.text().color() ) ); + } + + painter->restore(); +} + + +QSize MicroblogDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const +{ + Q_UNUSED( option ); + Q_UNUSED( index ); + + return QSize( 410, 210 ); +} +#include "microblogdelegate.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/microblogdelegate.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/microblogdelegate.h --- kde-nightly-kdepim-20091006+svn1032120/examples/akonablog/microblogdelegate.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/akonablog/microblogdelegate.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,53 @@ +/* + Copyright (c) 2009 Omat Holding B.V. + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include + +#ifndef MICROBLOGDELEGATE_H +#define MICROBLOGDELEGATE_H + +class BlogModel; + +class MicroblogDelegate : public KWidgetItemDelegate +{ + Q_OBJECT + +public: + MicroblogDelegate( QAbstractItemView *itemView, QObject * parent ); + + QList createItemWidgets() const; + + void updateItemWidgets( const QList widgets, + const QStyleOptionViewItem &option, + const QPersistentModelIndex &index ) const; + + void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const; + QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const; + + +private slots: + void slotLinkClicked( const QUrl &url ); + +private: + QVariant getData( const BlogModel*, int row, int column ) const; + QWidget* m_parent; +}; + +#endif + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/CMakeLists.txt 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,32 @@ +project(mailreader) + +set(mailreader_SRCS + mailreader.cpp + main.cpp + mailreaderview.cpp + ) + +include_directories( + ${CMAKE_SOURCE_DIR}/akonadi + ${Boost_INCLUDE_DIRS} +) + +kde4_add_ui_files(mailreader_SRCS mailreaderview.ui prefs_base.ui prefs_messagelist.ui) + +kde4_add_kcfg_files(mailreader_SRCS settings.kcfgc ) + +kde4_add_executable(akonadimailreader ${mailreader_SRCS}) + +target_link_libraries(akonadimailreader messageviewer messagelist kdepim kpgp kleo akonadi-kde akonadi_next ${KDE4_KDEUI_LIBS} ${KDE4_KHTML_LIBS} ${KDE4_KTNEF_LIBRARY} + ${QGPGME_LIBRARIES} +) + +install(TARGETS akonadimailreader ${INSTALL_TARGETS_DEFAULT_ARGS} ) + + + +########### install files ############### + +install( FILES mailreader.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) +install( FILES mailreader.kcfg DESTINATION ${KCFG_INSTALL_DIR} ) +install( FILES mailreaderui.rc DESTINATION ${DATA_INSTALL_DIR}/mailreader ) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/CMakeLists.txt 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,37 @@ +project(kpapplet) + +find_package(KDE4 REQUIRED) +find_package(Akonadi REQUIRED) +find_package(KdepimLibs REQUIRED) + +include_directories( + ${AKONADI_INCLUDE_DIR} + ${KDE4_INCLUDES} + ${KDEPIMLIBS_INCLUDE_DIRS} + ${QT_INCLUDES} + ${PROJECT_BINARY_DIR} + ${PROJECT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/libmailreader + ${CMAKE_SOURCE_DIR}/akonadi + ${Boost_INCLUDE_DIRS} + +) + +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) + +set(kpapplet_SRCS + kpapplet.cpp + kpdialog.cpp + ) + +kde4_add_plugin(plasma_applet_kpapplet ${kpapplet_SRCS}) + +target_link_libraries( + plasma_applet_kpapplet + ${KDE4_PLASMA_LIBS} + ${KDE4_KIO_LIBS} + messagelist kdepim kpgp kleo akonadi-kde akonadi_next +) + +install(TARGETS plasma_applet_kpapplet DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-applet-kpapplet.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/kpapplet.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/kpapplet.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/kpapplet.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/kpapplet.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright 2009 by Sebastian Kügler * + * * + * 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) any later version. * + * * + * 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 . * + ***************************************************************************/ + +//own +#include "kpapplet.h" +#include "kpdialog.h" + +//Qt +#include +#include + +//KDE +#include +#include +#include +#include + +//plasma +#include +//use for desktop view +#include +#include +#include + + +using namespace Plasma; +using namespace KP; + +K_EXPORT_PLASMA_APPLET(kpapplet, KPApplet) + +KPApplet::KPApplet(QObject *parent, const QVariantList &args) + : Plasma::PopupApplet(parent, args), + m_icon(0), + m_dialog(0) +{ + + + setBackgroundHints(StandardBackground); + setAspectRatioMode(IgnoreAspectRatio); + setHasConfigurationInterface(true); + setAcceptsHoverEvents(true); + + // initialize the widget + (void)widget(); +} + +KPApplet::~KPApplet() +{ + delete m_icon; + delete m_dialog; +} + +void KPApplet::init() +{ + KConfigGroup cg = config(); + + m_icon = new Plasma::IconWidget(KIcon("kmail",NULL), QString()); + + Plasma::ToolTipManager::self()->registerWidget(this); + + setPopupIcon(m_icon->icon()); + + updateToolTip(1337); +} + +QGraphicsWidget* KPApplet::graphicsWidget() +{ + if (!m_dialog) { + m_dialog = new KPDialog(this); + } + return m_dialog->dialog(); +} + +void KPApplet::popupEvent(bool show) +{ + if (show) { + kDebug() << "showing"; + } +} + +void KPApplet::updateToolTip(const int emails) +{ + + m_toolTip = Plasma::ToolTipContent(i18nc("Tooltip main title text", "Your emails"), + i18ncp("Tooltip sub text", "One new email", "%1 new emails", emails), + KIcon("kmail").pixmap(IconSize(KIconLoader::Desktop)) + ); + Plasma::ToolTipManager::self()->setContent(this, m_toolTip); +} + +#include "kpapplet.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/kpapplet.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/kpapplet.h --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/kpapplet.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/kpapplet.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright 2009 by Sebastian Kügler * + * * + * 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) any later version. * + * * + * 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 . * + ***************************************************************************/ + +#ifndef KPAPPLET_H +#define KPAPPLET_H + +//Plasma +#include +#include + + + +class QGraphicsProxyWidget; + +namespace KP +{ + class KPDialog; +} + +//desktop view +namespace Plasma +{ + class IconWidget; + class ToolTipContent; +} + +class KPApplet : public Plasma::PopupApplet +{ + Q_OBJECT + + public: + KPApplet(QObject *parent, const QVariantList &args); + ~KPApplet(); + void init(); + QGraphicsWidget *graphicsWidget(); + void updateToolTip(const int emails); + + protected: + void popupEvent(bool show); + + private: + ///the icon used when the applet is in the taskbar + Plasma::IconWidget *m_icon; + + ///The dialog displaying matches + KP::KPDialog * m_dialog; + + Plasma::ToolTipContent m_toolTip; + +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/kpdialog.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/kpdialog.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/kpdialog.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/kpdialog.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright 2009 by Sebastian Kügler * + * * + * 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) any later version. * + * * + * 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 . * + ***************************************************************************/ + +// Akonadi +#include "akonadi_next/entitytreeview.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +//Qt +#include +#include +#include + +//KDE +#include +#include +#include +#include +#include +#include + +//plasma +#include +#include +#include + + +//own +#include "kpdialog.h" +#include "kpapplet.h" + + +using namespace KP; +using namespace Plasma; + + +KPDialog::KPDialog(KPApplet * kpapplet, QGraphicsWidget *parent) + : QGraphicsWidget(parent), + m_tabs(0), + m_folderListWidget(0), + m_applet(kpapplet) +{ + (void)dialog(); + setMinimumSize(300, 400); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +KPDialog::~KPDialog() +{ +} + +QGraphicsWidget * KPDialog::dialog() +{ + if (!m_tabs) { + m_tabs = new Plasma::TabBar(this); + //m_tabs->setPreferredSize(300, 400); + //m_tabs->setMinimumSize(150, 200); + //m_tabs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + m_folderListWidget = new QWidget(); + QVBoxLayout *f_layout = new QVBoxLayout(m_folderListWidget); + m_folderListProxyWidget = new QGraphicsProxyWidget(m_tabs); + + m_messageListWidget = new QWidget(); + QVBoxLayout *m_layout = new QVBoxLayout(m_messageListWidget); + m_messageListProxyWidget = new QGraphicsProxyWidget(m_tabs); + + f_layout->setSpacing(0); + f_layout->setMargin(0); + + setupPane(); + f_layout->addWidget(m_folderListView); + + m_folderListProxyWidget->setWidget(m_folderListWidget); + m_tabs->addTab(i18n("Folders"), m_folderListProxyWidget); + + m_messageListProxyWidget->setWidget(m_messageListWidget); + m_layout->setSpacing(0); + m_layout->setMargin(0); + m_layout->addWidget(m_messagePane); + + m_tabs->addTab(i18n("Messages"), m_messageListProxyWidget); + + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(updateColors())); + updateColors(); + } + return m_tabs; +} + +void KPDialog::updateColors() +{ + QPalette p = m_folderListWidget->palette(); + p.setColor(QPalette::Window, Qt::transparent); + p.setColor(QPalette::Base, Qt::transparent); + //p.setColor(QPalette::Window, Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor)); + p.setColor(QPalette::WindowText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor)); + m_folderListWidget->setPalette(p); + m_folderListView->setPalette(p); + m_folderListView->setAttribute(Qt::WA_NoSystemBackground); + m_folderListWidget->setAttribute(Qt::WA_NoSystemBackground); + m_messageListWidget->setAttribute(Qt::WA_NoSystemBackground); + m_messageListWidget->setPalette(p); +} + +void KPDialog::setupPane() +{ + kDebug() << "Setting up"; + // Setup the core model + Akonadi::Session *session = new Akonadi::Session( "KPApplet", m_folderListWidget ); + + Akonadi::Monitor *monitor = new Akonadi::Monitor( m_folderListWidget ); + monitor->setCollectionMonitored( Akonadi::Collection::root() ); + monitor->fetchCollection( true ); + monitor->setMimeTypeMonitored( "message/rfc822", true ); + monitor->itemFetchScope().fetchFullPayload(true); + + Akonadi::EntityTreeModel *entityModel = new Akonadi::EntityTreeModel( session, monitor, m_folderListWidget ); + entityModel->setItemPopulationStrategy( Akonadi::EntityTreeModel::LazyPopulation ); + + // Create the collection view + m_folderListView = new Akonadi::EntityTreeView( 0, m_folderListWidget ); + m_folderListView->setSelectionMode( QAbstractItemView::ExtendedSelection ); + + + + // Setup the message folders collection... + Akonadi::EntityFilterProxyModel *collectionFilter = new Akonadi::EntityFilterProxyModel( m_folderListWidget ); + collectionFilter->setSourceModel( entityModel ); + //collectionFilter->addMimeTypeInclusionFilter( "message/rfc822" ); + collectionFilter->addMimeTypeInclusionFilter( Akonadi::Collection::mimeType() ); + collectionFilter->setHeaderSet( Akonadi::EntityTreeModel::CollectionTreeHeaders ); + + // ... with statistics... + Akonadi::StatisticsToolTipProxyModel *statisticsProxyModel = new Akonadi::StatisticsToolTipProxyModel( m_folderListWidget ); + statisticsProxyModel->setSourceModel( collectionFilter ); + + // ... and sortable + QSortFilterProxyModel *sortModel = new QSortFilterProxyModel( m_folderListWidget ); + sortModel->setDynamicSortFilter( true ); + sortModel->setSortCaseSensitivity( Qt::CaseInsensitive ); + sortModel->setSourceModel( statisticsProxyModel ); + // Use the model + m_folderListView->setModel( sortModel ); + entityModel->setRootCollection(Akonadi::Collection::root()); + + // Now make the message list multi-tab pane + m_messagePane = new MessageList::Pane( entityModel, m_folderListView->selectionModel(), m_messageListWidget ); + //connect( m_messagePane, SIGNAL(messageSelected(Akonadi::Item)), + // this, SLOT(slotMessageSelected(Akonadi::Item)) ); + +} +#include "kpdialog.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/kpdialog.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/kpdialog.h --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/kpdialog.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/kpdialog.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright 2009 by Sebastian Kügler * + * * + * 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) any later version. * + * * + * 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 . * + ***************************************************************************/ + +#ifndef KPDIALOG_H +#define KPDIALOG_H + +// Akonadi +#include +#include + +//Qt +#include +#include +#include +#include + +// KDE +#include +#include + + +//own +class KPApplet; + +//desktop view +namespace Plasma +{ + class Icon; + class Dialog; + class TabBar; +} + +namespace Akonadi +{ + class EntityTreeView; +} + +namespace MessageList +{ + class Pane; +} + +namespace KP +{ + /** + * @short KMail's message list in a popup applet + * + */ + class KPDialog : public QGraphicsWidget + { + Q_OBJECT + + public: + /** + * Constructor of the dialog + * @param kpapplet the KPApplet attached to this dialog + * @param parent the parent of this object + **/ + KPDialog(KPApplet * kpapplet, QGraphicsWidget *parent = 0); + + virtual ~KPDialog(); + + /** + * Returns the related QWidget. + **/ + QGraphicsWidget * dialog(); + + private Q_SLOTS: + /** + * @internal update the color of the label to follow plasma theme + * + **/ + void updateColors(); + + private : + /** + * @internal build the dialog depending where it is + **/ + void buildDialog(); + void setupPane(); + Plasma::TabBar* m_tabs; + QGraphicsProxyWidget *m_folderListProxyWidget; + QGraphicsProxyWidget *m_messageListProxyWidget; + QWidget *m_folderListWidget; + QWidget *m_messageListWidget; + KPushButton * m_button; + MessageList::Pane *m_messagePane; + Akonadi::EntityTreeView *m_folderListView; + KPApplet * m_applet; + }; +} + +#endif + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/Messages.sh /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/Messages.sh --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/Messages.sh 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/Messages.sh 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_applet_kpapplet.pot diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/plasma-applet-kpapplet.desktop /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/plasma-applet-kpapplet.desktop --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/kmail-plasma/plasma-applet-kpapplet.desktop 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/kmail-plasma/plasma-applet-kpapplet.desktop 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,81 @@ +[Desktop Entry] +Name=KMail +Name[af]=KMail +Name[be]=KMail +Name[bg]=KMail +Name[br]=KMail +Name[ca]=KMail +Name[cs]=KMail +Name[cy]=KMail +Name[da]=KMail +Name[de]=KMail +Name[el]=KMail +Name[en_GB]=KMail +Name[eo]=Retpoŝto +Name[es]=KMail +Name[et]=KMail +Name[eu]=KMail +Name[fi]=KMail +Name[fr]=KMail +Name[fy]=KMail +Name[ga]=KMail +Name[gl]=KMail +Name[he]=KMail +Name[hr]=KMail +Name[hu]=KMail +Name[is]=KMail +Name[it]=KMail +Name[ja]=KMail +Name[ka]=KMail +Name[kk]=KMail +Name[km]=KMail +Name[ko]=KMail +Name[lt]=KMail +Name[lv]=KMail +Name[mk]=КПошта +Name[ms]=KMail +Name[nb]=KMail +Name[nds]=KMail +Name[ne]=केडीई पत्र +Name[nl]=KMail +Name[nn]=KMail +Name[oc]=KMail +Name[pa]=ਕੇ-ਮੇਲ +Name[pl]=KMail +Name[pt]=KMail +Name[pt_BR]=KMail +Name[ro]=KMail +Name[ru]=KMail +Name[se]=KMail +Name[sk]=KMail +Name[sl]=KMail +Name[sv]=Kmail +Name[ta]=Kஅஞ்சல் +Name[tg]=KMail +Name[th]=จัดการจดหมาย K +Name[tr]=KMail +Name[uk]=KMail +Name[uz]=KMail +Name[uz@cyrillic]=KMail +Name[vi]=KMail +Name[wa]=KMail +Name[xh]=KMail +Name[x-test]=xxKMailxx +Name[zh_CN]=KMail +Name[zh_TW]=KMail 郵件軟體 +Comment=Your emails +Icon=kmail +Type=Service +X-KDE-ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_kpapplet +X-KDE-PluginInfo-Author=Sebastian Kügler +X-KDE-PluginInfo-Email=sebas@kde.org +X-KDE-PluginInfo-Name=kpapplet +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://pim.kde.org/ +X-KDE-PluginInfo-Category=Examples +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreader.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreader.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreader.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreader.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,168 @@ +/* + * mailreader.cpp + * + * Copyright (C) 2008 Andras Mantia + */ +#include "mailreader.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +#include "mailreaderview.h" +#include "settings.h" + + +mailreader::mailreader() + : KXmlGuiWindow(), + m_view(new mailreaderView(this)) +{ + // accept dnd + setAcceptDrops(true); + + // tell the KXmlGuiWindow that this is indeed the main widget + setCentralWidget(m_view); + + setupDocks(); + + // then, setup our actions + setupActions(); + + // add a status bar + statusBar()->show(); + + // a call to KXmlGuiWindow::setupGUI() populates the GUI + // with actions, using KXMLGUI. + // It also applies the saved mainwindow settings, if any, and ask the + // mainwindow to automatically save settings if changed: window size, + // toolbar position, icon size, etc. + setupGUI(); + +} + +mailreader::~mailreader() +{ +} + +void mailreader::setupDocks() +{ + // Setup the core model + Akonadi::Session *session = new Akonadi::Session( "AkonadiMailReader", this ); + + Akonadi::ChangeRecorder *monitor = new Akonadi::ChangeRecorder( this ); + monitor->setCollectionMonitored( Akonadi::Collection::root() ); + monitor->fetchCollection( true ); + monitor->setMimeTypeMonitored( "message/rfc822", true ); + monitor->itemFetchScope().fetchFullPayload(true); + + Akonadi::EntityTreeModel *entityModel = new Akonadi::EntityTreeModel( session, monitor, this ); + entityModel->setItemPopulationStrategy( Akonadi::EntityTreeModel::LazyPopulation ); + + // Create the collection view + Akonadi::EntityTreeView *collectionView = new Akonadi::EntityTreeView( 0, this ); + collectionView->setSelectionMode( QAbstractItemView::ExtendedSelection ); + + // Setup the message folders collection... + Akonadi::EntityFilterProxyModel *collectionFilter = new Akonadi::EntityFilterProxyModel( this ); + collectionFilter->setSourceModel( entityModel ); + collectionFilter->addMimeTypeInclusionFilter( Akonadi::Collection::mimeType() ); + collectionFilter->setHeaderSet( Akonadi::EntityTreeModel::CollectionTreeHeaders ); + + // ... with statistics... + Akonadi::StatisticsToolTipProxyModel *statisticsProxyModel = new Akonadi::StatisticsToolTipProxyModel( this ); + statisticsProxyModel->setSourceModel( collectionFilter ); + + // ... and sortable + QSortFilterProxyModel *sortModel = new QSortFilterProxyModel( this ); + sortModel->setDynamicSortFilter( true ); + sortModel->setSortCaseSensitivity( Qt::CaseInsensitive ); + sortModel->setSourceModel( statisticsProxyModel ); + + // Use the model + collectionView->setModel( sortModel ); + + // Now make the message list multi-tab pane + m_messagePane = new MessageList::Pane( entityModel, collectionView->selectionModel(), this ); + connect( m_messagePane, SIGNAL(messageSelected(Akonadi::Item)), + this, SLOT(slotMessageSelected(Akonadi::Item)) ); + + // Dock the message list view + QDockWidget *messageListDock = new QDockWidget( i18n("Messages"), this ); + messageListDock->setObjectName( "Messages" ); + messageListDock->setWidget( m_messagePane ); + messageListDock->setFeatures( QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable ); + addDockWidget( Qt::TopDockWidgetArea, messageListDock ); + + // Dock the folder tree view + QDockWidget *folderDock = new QDockWidget( i18n("Folders"), this ); + folderDock->setObjectName( "Folders" ); + folderDock->setWidget( collectionView ); + folderDock->setFeatures( QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable ); + addDockWidget( Qt::LeftDockWidgetArea, folderDock ); + + // Fine tuning on the dock policy (nesting + corners) + setDockNestingEnabled( true ); + setCorner( Qt::TopLeftCorner, Qt::LeftDockWidgetArea ); + setCorner( Qt::BottomLeftCorner, Qt::LeftDockWidgetArea ); + setCorner( Qt::TopRightCorner, Qt::RightDockWidgetArea ); + setCorner( Qt::BottomRightCorner, Qt::RightDockWidgetArea ); +} + +void mailreader::setupActions() +{ + KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollection()); + KStandardAction::preferences(m_view, SLOT(slotConfigure()), actionCollection()); + + KAction *createTab = new KAction(KIcon("tab-new"), + i18n("Open a new tab"), + this); + actionCollection()->addAction("new_tab", createTab); + connect(createTab, SIGNAL(triggered(bool)), + m_messagePane, SLOT(createNewTab())); + + + m_previousMessage = new KAction(i18n("Previous Message"), this); + actionCollection()->addAction("previous_message", m_previousMessage); + connect(m_previousMessage, SIGNAL(triggered( bool )), SLOT(slotPreviousMessage())); + m_nextMessage = new KAction(i18n("Next Message"), this); + actionCollection()->addAction("next_message", m_nextMessage); + connect(m_nextMessage, SIGNAL(triggered( bool )), SLOT(slotNextMessage())); +} + +void mailreader::slotMessageSelected( const Akonadi::Item &item ) +{ + m_view->showItem( item ); +} + +void mailreader::slotPreviousMessage() +{ + m_messagePane->selectPreviousMessageItem( MessageList::Core::MessageTypeAny, + MessageList::Core::ClearExistingSelection, + true, true ); +} + +void mailreader::slotNextMessage() +{ + m_messagePane->selectNextMessageItem( MessageList::Core::MessageTypeAny, + MessageList::Core::ClearExistingSelection, + true, true ); +} + +#include "mailreader.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreader.desktop /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreader.desktop --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreader.desktop 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreader.desktop 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=mailreader +Exec=mailreader %i -caption "%c" +Icon=mailreader +Type=Application +X-DocPath=mailreader/index.html +GenericName=A KDE4 Application +Terminal=false diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreader.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreader.h --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreader.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreader.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,65 @@ +/* + * mailreader.h + * + * Copyright (C) 2008 Andras Mantia + */ +#ifndef MAILREADER_H +#define MAILREADER_H + + +#include + +#include +#include + +class mailreaderView; +class KToggleAction; +class KUrl; +class KComboBox; +class KAction; + +namespace MessageList +{ + class Pane; +} + +/** + * This class serves as the main window for mailreader. It handles the + * menus, toolbars, and status bars. + * + * @short Main window class + * @author Andras Mantia + * @version 0.1 + */ +class mailreader : public KXmlGuiWindow +{ + Q_OBJECT +public: + /** + * Default Constructor + */ + mailreader(); + + /** + * Default Destructor + */ + virtual ~mailreader(); + +private slots: + void slotMessageSelected(const Akonadi::Item &item); + void slotPreviousMessage(); + void slotNextMessage(); + +private: + void setupDocks(); + void setupActions(); + +private: + mailreaderView *m_view; + MessageList::Pane *m_messagePane; + + KAction *m_nextMessage; + KAction *m_previousMessage; +}; + +#endif // _MAILREADER_H_ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreader.kcfg /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreader.kcfg --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreader.kcfg 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreader.kcfg 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,21 @@ + + + + + + + black + + + + yellow + + + + 2 + + + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreaderui.rc /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreaderui.rc --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreaderui.rc 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreaderui.rc 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,15 @@ + + + + + + + + + + Navigation Toolbar + + + + + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreaderview.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreaderview.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreaderview.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreaderview.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,108 @@ +/* + * mailreaderview.cpp + * + * Copyright (C) 2009 Andras Mantia + */ +#include "mailreaderview.h" +#include "settings.h" +#include "messageviewer/viewer.h" +#include "messageviewer/attachmentstrategy.h" +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "messagelist/core/settings.h" +#include "ui_prefs_messagelist.h" + +mailreaderView::mailreaderView(QWidget *parent) +{ + ui_mailreaderview.setupUi(this); + QHBoxLayout *layout = new QHBoxLayout; + m_readerWin = new MessageViewer::Viewer( this, KSharedConfig::openConfig("mailreaderrc"), parent, dynamic_cast(parent)->actionCollection()); + m_readerWin->setAttachmentStrategy( MessageViewer::AttachmentStrategy::inlined() ); + layout->addWidget(m_readerWin); + setLayout(layout); + setAutoFillBackground(true); + displayAboutPage(); + connect( m_readerWin, SIGNAL(urlClicked(const KUrl&, int)), this, SLOT(urlClicked(const KUrl&, int))); +} + +mailreaderView::~mailreaderView() +{ + +} + +void mailreaderView::switchColors() +{ + // switch the foreground/background colors of the label + QColor color = Settings::col_background(); + Settings::setCol_background( Settings::col_foreground() ); + Settings::setCol_foreground( color ); + + settingsChanged(); +} + +void mailreaderView::settingsChanged() +{ +} + +void mailreaderView::showItem(const Akonadi::Item& item) +{ + kDebug() << "Show item with ID: " << item.id(); + m_readerWin->enableMessageDisplay(); + m_readerWin->setDecryptMessageOverwrite( false ); + m_readerWin->setMessageItem(item, MessageViewer::Viewer::Force); +} + +void mailreaderView::showAboutPage() +{ + displayAboutPage(); +} + +void mailreaderView::displayAboutPage() +{ + KLocalizedString info = + ki18nc("%1: Mailreader version;" + "--- end of comment ---", + "

Welcome to Mailreader %1

" + "

Mailread is a proof of concept reader for the Akonadi/KMime framework.

\n" + "

    The Akonadi Team

") + .subs( "0.1" ); // Akonadi Mail Reader version + + m_readerWin->displaySplashPage( info.toString() ); +} + +void mailreaderView::urlClicked( const KUrl& url, int button) +{ + kDebug() << url << " clicked in the mail viewer"; +} + +void mailreaderView::slotConfigure() +{ + if(KConfigDialog::showDialog("mailviewersettings")) + return; + KConfigDialog *dialog = new KConfigDialog( this, "mailviewersettings", m_readerWin->configObject() ); + QWidget* widget = m_readerWin->configWidget(); + dialog->addPage( widget, i18n("Viewer"), "kmail"); + + QWidget *messageListConfig = new QWidget(dialog); + Ui::MessageListConfig ui; + ui.setupUi(messageListConfig); + dialog->addPage(messageListConfig, + MessageList::Core::Settings::self(), + i18n("Message List"), + "kmail"); + + connect( dialog, SIGNAL(settingsChanged(const QString& )), + widget, SLOT(slotSettingsChanged()) ); + dialog->setAttribute( Qt::WA_DeleteOnClose ); + dialog->show(); +} + +#include "mailreaderview.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreaderview.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreaderview.h --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreaderview.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreaderview.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,77 @@ +/* + * mailreaderview.h + * + * Copyright (C) 2009 Andras Mantia + */ +#ifndef MAILREADERVIEW_H +#define MAILREADERVIEW_H + +#include + +#include "ui_mailreaderview.h" + +class QPainter; +class KUrl; + +namespace MessageViewer { + class Viewer; +} + +namespace Akonadi { + class Item; +} + +/** + * This is the main view class for mailreader. Most of the non-menu, + * non-toolbar, and non-statusbar (e.g., non frame) GUI code should go + * here. + * + * @short Main view + * @author Andras Mantia + * @version 0.1 + */ + +class mailreaderView : public QWidget, public Ui::mailreaderview +{ + Q_OBJECT +public: + /** + * Default constructor + */ + mailreaderView(QWidget *parent); + + /** + * Destructor + */ + virtual ~mailreaderView(); + + void showItem(const Akonadi::Item& item); + void showAboutPage(); + +private: + void displayAboutPage(); + + Ui::mailreaderview ui_mailreaderview; + MessageViewer::Viewer *m_readerWin; + +public slots: + void slotConfigure(); + +signals: + /** + * Use this signal to change the content of the statusbar + */ + void signalChangeStatusbar(const QString& text); + + /** + * Use this signal to change the content of the caption + */ + void signalChangeCaption(const QString& text); + +private slots: + void switchColors(); + void settingsChanged(); + void urlClicked( const KUrl& url, int button); +}; + +#endif // mailreaderVIEW_H diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreaderview.ui /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreaderview.ui --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/mailreaderview.ui 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/mailreaderview.ui 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,16 @@ + + + mailreaderview + + + + 0 + 0 + 400 + 300 + + + + + + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/main.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/main.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/main.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/main.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,53 @@ +#include "mailreader.h" +#include +#include +#include +#include + +static const char description[] = + I18N_NOOP("A KDE 4 Application"); + +static const char version[] = "0.1"; + +int main(int argc, char **argv) +{ + KAboutData about("mailreader", 0, ki18n("mailreader"), version, ki18n(description), + KAboutData::License_GPL, ki18n("(C) 2007 Andras Mantia"), KLocalizedString(), 0, "amantia@kde.org"); + about.addAuthor( ki18n("Andras Mantia"), KLocalizedString(), "amantia@kde.org" ); + KCmdLineArgs::init(argc, argv, &about); + + KCmdLineOptions options; + options.add("+[URL]", ki18n( "Document to open" )); + KCmdLineArgs::addCmdLineOptions(options); + KApplication app; + + mailreader *widget = new mailreader; + + // see if we are starting with session management + if (app.isSessionRestored()) + { + RESTORE(mailreader); + } + else + { + // no session.. just start up normally + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + if (args->count() == 0) + { + //mailreader *widget = new mailreader; + widget->show(); + } + else + { + int i = 0; + for (; i < args->count(); i++) + { + //mailreader *widget = new mailreader; + widget->show(); + } + } + args->clear(); + } + + return app.exec(); +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/Messages.sh /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/Messages.sh --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/Messages.sh 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/Messages.sh 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp +$XGETTEXT *.cpp -o $podir/mailreader.pot +rm -f *.cpp diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/prefs_base.ui /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/prefs_base.ui --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/prefs_base.ui 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/prefs_base.ui 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,153 @@ + + prefs_base + + + + 0 + 0 + 282 + 156 + + + + + + + Background color: + + + false + + + + + + + Choose a new background color + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Change the <span style=" font-weight:600;">background</span> color by clicking here and choose the new <span style=" color:#ff0000;">color</span> in the <span style=" font-style:italic;">color dialog</span>.</p></body></html> + + + + + + + + + + Project age: + + + false + + + + + + + Foreground color: + + + false + + + + + + + Choose a new foreground color + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Change the <span style=" font-weight:600;">foreground</span> color by clicking here and choose the new <span style=" color:#ff0000;">color</span> in the <span style=" font-style:italic;">color dialog</span>.</p></body></html> + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 41 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 41 + 20 + + + + + + + + Set the project age (in days) + + + Change the project age (in days) by choosing a new number of days. + + + 1 + + + 2 + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 41 + 20 + + + + + + + + + KColorButton + QPushButton +
kcolorbutton.h
+
+
+ + kcolorbutton.h + + + +
diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/prefs_messagelist.ui /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/prefs_messagelist.ui --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/prefs_messagelist.ui 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/prefs_messagelist.ui 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,331 @@ + + + MessageListConfig + + + + 0 + 0 + 573 + 565 + + + + + + + General + + + + + + Display tooltips for messages and group headers + + + + + + + Hide tab bar when only one tab is open + + + + + + + + + + Colors + + + + + + + + Use default colors + + + + + + + New messages: + + + + + + + + + + Unread messages: + + + + + + + + + + Important messages: + + + + + + + + + + Action messages: + + + + + + + + + + + + + + + Fonts + + + + + + QFormLayout::ExpandingFieldsGrow + + + + + Use default fonts + + + + + + + Message list: + + + + + + + New messages: + + + + + + + Unread messages: + + + + + + + Important messages: + + + + + + + Action messages: + + + + + + + + + + + + + + + + + + + + + + + + + + + + KFontRequester + QWidget +
kfontrequester.h
+
+ + KColorButton + QPushButton +
kcolorbutton.h
+
+
+ + + + kcfg_UseDefaultColors + toggled(bool) + kcfg_NewMessageColor + setDisabled(bool) + + + 66 + 141 + + + 170 + 177 + + + + + kcfg_UseDefaultColors + toggled(bool) + kcfg_UnreadMessageColor + setDisabled(bool) + + + 37 + 141 + + + 163 + 205 + + + + + kcfg_UseDefaultColors + toggled(bool) + kcfg_ImportantMessageColor + setDisabled(bool) + + + 107 + 143 + + + 158 + 231 + + + + + kcfg_UseDefaultColors + toggled(bool) + kcfg_TodoMessageColor + setDisabled(bool) + + + 83 + 147 + + + 159 + 263 + + + + + kcfg_UseDefaultFonts + toggled(bool) + kcfg_MessageListFont + setDisabled(bool) + + + 75 + 373 + + + 186 + 405 + + + + + kcfg_UseDefaultFonts + toggled(bool) + kcfg_NewMessageFont + setDisabled(bool) + + + 54 + 376 + + + 158 + 434 + + + + + kcfg_UseDefaultFonts + toggled(bool) + kcfg_UnreadMessageFont + setDisabled(bool) + + + 35 + 379 + + + 157 + 462 + + + + + kcfg_UseDefaultFonts + toggled(bool) + kcfg_ImportantMessageFont + setDisabled(bool) + + + 21 + 376 + + + 158 + 492 + + + + + kcfg_UseDefaultFonts + toggled(bool) + kcfg_TodoMessageFont + setDisabled(bool) + + + 94 + 374 + + + 155 + 517 + + + + +
diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/settings.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/settings.cpp --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/settings.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/settings.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,51 @@ +// This file is generated by kconfig_compiler from mailreader.kcfg. +// All changes you do to this file will be lost. + +#include "settings.h" + +#include +#include + +class SettingsHelper +{ + public: + SettingsHelper() : q(0) {} + ~SettingsHelper() { delete q; } + Settings *q; +}; +K_GLOBAL_STATIC(SettingsHelper, s_globalSettings) +Settings *Settings::self() +{ + if (!s_globalSettings->q) { + new Settings; + s_globalSettings->q->readConfig(); + } + + return s_globalSettings->q; +} + +Settings::Settings( ) + : KConfigSkeleton( QLatin1String( "mailreaderrc" ) ) +{ + Q_ASSERT(!s_globalSettings->q); + s_globalSettings->q = this; + setCurrentGroup( QLatin1String( "Preferences" ) ); + + KConfigSkeleton::ItemColor *itemCol_background; + itemCol_background = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "col_background" ), mCol_background, QColor( "black" ) ); + addItem( itemCol_background, QLatin1String( "col_background" ) ); + KConfigSkeleton::ItemColor *itemCol_foreground; + itemCol_foreground = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "col_foreground" ), mCol_foreground, QColor( "yellow" ) ); + addItem( itemCol_foreground, QLatin1String( "col_foreground" ) ); + KConfigSkeleton::ItemInt *itemVal_time; + itemVal_time = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "val_time" ), mVal_time, 2 ); + addItem( itemVal_time, QLatin1String( "val_time" ) ); +} + +Settings::~Settings() +{ + if (!s_globalSettings.isDestroyed()) { + s_globalSettings->q = 0; + } +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/settings.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/settings.h --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/settings.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/settings.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,78 @@ +// This file is generated by kconfig_compiler from mailreader.kcfg. +// All changes you do to this file will be lost. +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include + +class Settings : public KConfigSkeleton +{ + public: + + static Settings *self(); + ~Settings(); + + /** + Set color of the background + */ + static + void setCol_background( const QColor & v ) + { + if (!self()->isImmutable( QString::fromLatin1 ( "col_background" ) )) + self()->mCol_background = v; + } + + /** + Get color of the background + */ + static + QColor col_background() + { + return self()->mCol_background; + } + + /** + Set color of the foreground + */ + static + void setCol_foreground( const QColor & v ) + { + if (!self()->isImmutable( QString::fromLatin1 ( "col_foreground" ) )) + self()->mCol_foreground = v; + } + + /** + Get color of the foreground + */ + static + QColor col_foreground() + { + return self()->mCol_foreground; + } + + + /** + Get size of a ball + */ + static + int val_time() + { + return self()->mVal_time; + } + + protected: + Settings(); + friend class SettingsHelper; + + + // Preferences + QColor mCol_background; + QColor mCol_foreground; + int mVal_time; + + private: +}; + +#endif + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/settings.kcfgc /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/settings.kcfgc --- kde-nightly-kdepim-20091006+svn1032120/examples/mailreader/settings.kcfgc 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/examples/mailreader/settings.kcfgc 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,6 @@ +# Code generation options for kconfig_compiler +File=mailreader.kcfg +ClassName=Settings +Singleton=true +Mutators=col_background,col_foreground +# will create the necessary code for setting those variables diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/alarmcalendar.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/alarmcalendar.cpp --- kde-nightly-kdepim-20091006+svn1032120/kalarm/alarmcalendar.cpp 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/alarmcalendar.cpp 2009-10-09 23:31:00.000000000 +0100 @@ -1546,3 +1546,22 @@ // Now update the earliest alarm to trigger for its resource findEarliestAlarm(AlarmResources::instance()->resourceForIncidence(id)); } + +/****************************************************************************** +* Called when the user changes the start-of-day time. +* Adjust the start times of all date-only alarms' recurrences. +*/ +void AlarmCalendar::adjustStartOfDay() +{ + if (!mCalendar) + return; + for (ResourceMap::ConstIterator rit = mResourceMap.constBegin(); rit != mResourceMap.constEnd(); ++rit) + { + const KAEvent::List events = rit.value(); + for (int i = 0, end = events.count(); i < end; ++i) + { + if (events[i]->startDateTime().isDateOnly() && events[i]->recurs()) + events[i]->adjustRecurrenceStartOfDay(); + } + } +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/alarmcalendar.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/alarmcalendar.h --- kde-nightly-kdepim-20091006+svn1032120/kalarm/alarmcalendar.h 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/alarmcalendar.h 2009-10-09 23:31:00.000000000 +0100 @@ -83,6 +83,7 @@ bool isEmpty() const; QString path() const { return (mCalType == RESOURCES) ? QString() : mUrl.prettyUrl(); } QString urlString() const { return (mCalType == RESOURCES) ? QString() : mUrl.url(); } + void adjustStartOfDay(); static bool initialiseCalendars(); static void terminateCalendars(); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/alarmevent.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/alarmevent.h --- kde-nightly-kdepim-20091006+svn1032120/kalarm/alarmevent.h 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/alarmevent.h 2009-10-09 23:31:00.000000000 +0100 @@ -240,6 +240,7 @@ { return mEventData->setRecurAnnualByDate(freq, months, day, f, count, end); } bool setRecurAnnualByPos(int freq, const QList& pos, const QList& months, int count, const QDate& end) { return mEventData->setRecurAnnualByPos(freq, pos, months, count, end); } + void adjustRecurrenceStartOfDay() { mEventData->adjustRecurrenceStartOfDay(); } #ifdef NDEBUG void dumpDebug() const { } #else diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/cal/kaeventdata.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/cal/kaeventdata.cpp --- kde-nightly-kdepim-20091006+svn1032120/kalarm/cal/kaeventdata.cpp 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/cal/kaeventdata.cpp 2009-10-09 23:31:00.000000000 +0100 @@ -35,8 +35,8 @@ // KAlarm version which first used the current calendar/event format. // If this changes, KAEventData::convertKCalEvents() must be changed correspondingly. // The string version is the KAlarm version string used in the calendar file. -QByteArray KAEventData::currentCalendarVersionString() { return QByteArray("1.9.10"); } -int KAEventData::currentCalendarVersion() { return KAlarm::Version(1,9,10); } +QByteArray KAEventData::currentCalendarVersionString() { return QByteArray("2.2.9"); } +int KAEventData::currentCalendarVersion() { return KAlarm::Version(2,2,9); } QByteArray KAEventData::icalProductId() { @@ -1250,14 +1250,17 @@ /* Always set DTSTART as date/time, and use the category "DATE" to indicate * a date-only event, instead of calling setAllDay(). This is necessary to - * allow the alarm to float within the 24-hour period defined by the - * start-of-day time rather than midnight to midnight. + * allow a time zone to be specified for a date-only event. Also, KAlarm + * allows the alarm to float within the 24-hour period defined by the + * start-of-day time (which is user-dependent and therefore can't be + * written into the calendar) rather than midnight to midnight, and there + * is no RFC2445 conformant way to specify this. * RFC2445 states that alarm trigger times specified in absolute terms * (rather than relative to DTSTART or DTEND) can only be specified as a * UTC DATE-TIME value. So always use a time relative to DTSTART instead of * an absolute time. */ - ev->setDtStart(mStartDateTime.effectiveKDateTime()); + ev->setDtStart(mStartDateTime.calendarKDateTime()); ev->setAllDay(false); ev->setHasEndDate(false); @@ -1296,7 +1299,7 @@ { DateTime dtl; if (mArchiveRepeatAtLogin) - dtl = mStartDateTime.effectiveKDateTime().addDays(-1); + dtl = mStartDateTime.calendarKDateTime().addDays(-1); else if (mAtLoginDateTime.isValid()) dtl = mAtLoginDateTime; else if (mStartDateTime.isDateOnly()) @@ -1343,12 +1346,12 @@ QStringList list; if (mDeferralTime.isDateOnly()) { - startOffset = nextDateTime.secsTo(mDeferralTime.effectiveKDateTime()); + startOffset = nextDateTime.secsTo(mDeferralTime.calendarKDateTime()); list += DATE_DEFERRAL_TYPE; } else { - startOffset = nextDateTime.effectiveKDateTime().secsTo(mDeferralTime.effectiveKDateTime()); + startOffset = nextDateTime.calendarKDateTime().secsTo(mDeferralTime.calendarKDateTime()); list += TIME_DEFERRAL_TYPE; } if (mDeferral == REMINDER_DEFERRAL) @@ -1427,7 +1430,7 @@ Alarm* KAEventData::initKCalAlarm(Event* event, const DateTime& dt, const QStringList& types, KAAlarm::Type type) const { int startOffset = dt.isDateOnly() ? mStartDateTime.secsTo(dt) - : mStartDateTime.effectiveKDateTime().secsTo(dt.effectiveKDateTime()); + : mStartDateTime.calendarKDateTime().secsTo(dt.calendarKDateTime()); return initKCalAlarm(event, startOffset, types, type); } @@ -2025,7 +2028,7 @@ if (mStartDateTime.isDateOnly()) { QDate pre = preDateTime.date(); - if (preDateTime.time() < startOfDay) + if (preDateTime.toTimeSpec(mStartDateTime.timeSpec()).time() < startOfDay) pre = pre.addDays(-1); // today's recurrence (if today recurs) is still to come if (pre < dt.date()) return true; @@ -2141,7 +2144,7 @@ else { KDateTime recurStart = mRecurrence->startDateTime(); - KDateTime after = afterDateTime; + KDateTime after = afterDateTime.toTimeSpec(mStartDateTime.timeSpec()); if (mStartDateTime.isDateOnly() && afterDateTime.time() > startOfDay) after = after.addDays(1); // today's recurrence (if today recurs) has passed KDateTime dt = mRecurrence->getPreviousDateTime(after); @@ -2266,7 +2269,7 @@ KAEventData::OccurType KAEventData::nextRecurrence(const KDateTime& preDateTime, DateTime& result, const QTime& startOfDay) const { KDateTime recurStart = mRecurrence->startDateTime(); - KDateTime pre = preDateTime; + KDateTime pre = preDateTime.toTimeSpec(mStartDateTime.timeSpec()); if (mStartDateTime.isDateOnly() && !pre.isDateOnly() && pre.time() < startOfDay) { pre = pre.addDays(-1); // today's recurrence (if today recurs) is still to come @@ -2384,10 +2387,10 @@ DateTime next; nextRecurrence(mNextMainDateTime.effectiveKDateTime(), next, startOfDay); if (!next.isValid()) - mRecurrence->setStartDateTime(recurStart); // reinstate the old value + mRecurrence->setStartDateTime(recurStart, mStartDateTime.isDateOnly()); // reinstate the old value else { - mRecurrence->setStartDateTime(next.effectiveKDateTime()); + mRecurrence->setStartDateTime(next.effectiveKDateTime(), next.isDateOnly()); mStartDateTime = mNextMainDateTime = next; mUpdated = changed = true; } @@ -2408,8 +2411,7 @@ if (recurrence.recurs()) { mRecurrence = new KARecurrence(recurrence); - mRecurrence->setStartDateTime(mStartDateTime.effectiveKDateTime()); - mRecurrence->setAllDay(mStartDateTime.isDateOnly()); + mRecurrence->setStartDateTime(mStartDateTime.effectiveKDateTime(), mStartDateTime.isDateOnly()); mChanged = true; } else @@ -2429,6 +2431,16 @@ } /****************************************************************************** +* Called when the user changes the start-of-day time. +* Adjust the start time of a date-only alarm's recurrence. +*/ +void KAEventData::adjustRecurrenceStartOfDay() +{ + if (mRecurrence) + mRecurrence->setStartDateTime(mStartDateTime.effectiveKDateTime(), mStartDateTime.isDateOnly()); +} + +/****************************************************************************** * Initialise the event's sub-repetition. * The repetition length is adjusted if necessary to fit the recurrence interval. * Reply = false if a non-daily interval was specified for a date-only recurrence. @@ -2774,95 +2786,13 @@ #endif /****************************************************************************** - * Adjust the time at which date-only events will occur for each of the events - * in a list. Events for which both date and time are specified are left - * unchanged. - * Reply = true if any events have been updated. - */ -bool KAEventData::adjustStartOfDay(const Event::List& events, const QTime& startOfDay, const KTimeZone& timeZone) -{ - bool changed = false; - for (int ei = 0, eend = events.count(); ei < eend; ++ei) - { - Event* event = events[ei]; - QStringList flags = event->customProperty(KCalendar::APPNAME, FLAGS_PROPERTY).split(SC, QString::SkipEmptyParts); - if (flags.indexOf(DATE_ONLY_FLAG) >= 0) - { - // It's an untimed event, so fix it - QTime oldTime = event->dtStart().time(); - int adjustment = oldTime.secsTo(startOfDay); - if (adjustment) - { - event->setDtStart(KDateTime(event->dtStart().date(), startOfDay, timeZone)); - Alarm::List alarms = event->alarms(); - int deferralOffset = 0; - for (int ai = 0, aend = alarms.count(); ai < aend; ++ai) - { - // Parse the next alarm's text - Alarm* alarm = alarms[ai]; - AlarmData data; - readAlarm(alarm, data); - if (data.type & KAAlarm::TIMED_DEFERRAL_FLAG) - { - // Timed deferral alarm, so adjust the offset - deferralOffset = alarm->startOffset().asSeconds(); - alarm->setStartOffset(deferralOffset - adjustment); - } - else if (data.type == KAAlarm::AUDIO__ALARM - && alarm->startOffset().asSeconds() == deferralOffset) - { - // Audio alarm is set for the same time as the deferral alarm - alarm->setStartOffset(deferralOffset - adjustment); - } - } - changed = true; - } - } - else - { - // It's a timed event. Fix any untimed alarms. - int deferralOffset = 0; - int newDeferralOffset = 0; - DateTime start; - KDateTime nextMainDateTime = readDateTime(event, false, start).kDateTime(); - AlarmMap alarmMap; - readAlarms(event, &alarmMap); - for (AlarmMap::Iterator it = alarmMap.begin(); it != alarmMap.end(); ++it) - { - const AlarmData& data = it.value(); - if (!data.alarm->hasStartOffset()) - continue; - if ((data.type & KAAlarm::DEFERRED_ALARM) - && !(data.type & KAAlarm::TIMED_DEFERRAL_FLAG)) - { - // Date-only deferral alarm, so adjust its time - KDateTime altime = data.alarm->startOffset().end(nextMainDateTime); - altime.setTime(startOfDay); - deferralOffset = data.alarm->startOffset().asSeconds(); - newDeferralOffset = event->dtStart().secsTo(altime); - const_cast(data.alarm)->setStartOffset(newDeferralOffset); - changed = true; - } - else if (data.type == KAAlarm::AUDIO__ALARM - && data.alarm->startOffset().asSeconds() == deferralOffset) - { - // Audio alarm is set for the same time as the deferral alarm - const_cast(data.alarm)->setStartOffset(newDeferralOffset); - changed = true; - } - } - } - } - return changed; -} - -/****************************************************************************** * If the calendar was written by a previous version of KAlarm, do any * necessary format conversions on the events to ensure that when the calendar * is saved, no information is lost or corrupted. * Reply = true if any conversions were done. */ -bool KAEventData::convertKCalEvents(KCal::CalendarLocal& calendar, int version, bool adjustSummerTime, const QTime& startOfDay) +bool KAEventData::convertKCalEvents(KCal::CalendarLocal& calendar, int calendarVersion, + bool adjustSummerTime, const QTime& startOfDay, const KTimeZone& timeZone) { // KAlarm pre-0.9 codes held in the alarm's DESCRIPTION property static const QChar SEPARATOR = QLatin1Char(';'); @@ -2902,25 +2832,28 @@ // KAlarm pre-1.5.0/1.9.9 properties static const QByteArray KMAIL_ID_PROPERTY("KMAILID"); // X-KDE-KALARM-KMAILID property - if (version >= currentCalendarVersion()) + if (calendarVersion >= currentCalendarVersion()) return false; - kDebug() << "Adjusting version" << version; - bool pre_0_7 = (version < KAlarm::Version(0,7,0)); - bool pre_0_9 = (version < KAlarm::Version(0,9,0)); - bool pre_0_9_2 = (version < KAlarm::Version(0,9,2)); - bool pre_1_1_1 = (version < KAlarm::Version(1,1,1)); - bool pre_1_2_1 = (version < KAlarm::Version(1,2,1)); - bool pre_1_3_0 = (version < KAlarm::Version(1,3,0)); - bool pre_1_3_1 = (version < KAlarm::Version(1,3,1)); - bool pre_1_4_14 = (version < KAlarm::Version(1,4,14)); - bool pre_1_5_0 = (version < KAlarm::Version(1,5,0)); - bool pre_1_9_0 = (version < KAlarm::Version(1,9,0)); - bool pre_1_9_2 = (version < KAlarm::Version(1,9,2)); - bool pre_1_9_7 = (version < KAlarm::Version(1,9,7)); - bool pre_1_9_9 = (version < KAlarm::Version(1,9,9)); - bool pre_1_9_10 = (version < KAlarm::Version(1,9,10)); - Q_ASSERT(currentCalendarVersion() == KAlarm::Version(1,9,10)); + kDebug() << "Adjusting version" << calendarVersion; + bool pre_0_7 = (calendarVersion < KAlarm::Version(0,7,0)); + bool pre_0_9 = (calendarVersion < KAlarm::Version(0,9,0)); + bool pre_0_9_2 = (calendarVersion < KAlarm::Version(0,9,2)); + bool pre_1_1_1 = (calendarVersion < KAlarm::Version(1,1,1)); + bool pre_1_2_1 = (calendarVersion < KAlarm::Version(1,2,1)); + bool pre_1_3_0 = (calendarVersion < KAlarm::Version(1,3,0)); + bool pre_1_3_1 = (calendarVersion < KAlarm::Version(1,3,1)); + bool pre_1_4_14 = (calendarVersion < KAlarm::Version(1,4,14)); + bool pre_1_5_0 = (calendarVersion < KAlarm::Version(1,5,0)); + bool pre_1_9_0 = (calendarVersion < KAlarm::Version(1,9,0)); + bool pre_1_9_2 = (calendarVersion < KAlarm::Version(1,9,2)); + bool pre_1_9_7 = (calendarVersion < KAlarm::Version(1,9,7)); + bool pre_1_9_9 = (calendarVersion < KAlarm::Version(1,9,9)); + bool pre_1_9_10 = (calendarVersion < KAlarm::Version(1,9,10)); + bool pre_2_2_9 = (calendarVersion < KAlarm::Version(2,2,9)); + bool pre_2_3_0 = (calendarVersion < KAlarm::Version(2,3,0)); + bool pre_2_3_2 = (calendarVersion < KAlarm::Version(2,3,2)); + Q_ASSERT(currentCalendarVersion() == KAlarm::Version(2,2,9)); KTimeZone localZone; if (pre_1_9_2) @@ -3391,6 +3324,16 @@ } #endif + if (pre_2_2_9 || (pre_2_3_2 && !pre_2_3_0)) + { + /* + * It's a KAlarm pre-2.2.9 or KAlarm 2.3 series pre-2.3.2 calendar file. + * Set the time in the calendar for all date-only alarms to 00:00. + */ + if (convertStartOfDay(event, timeZone)) + converted = true; + } + if (readOnly) event->setReadOnly(true); event->endUpdates(); // finally issue an update notification @@ -3398,6 +3341,84 @@ return converted; } +/****************************************************************************** +* Set the time for a date-only event to 00:00. +* Reply = true if the event was updated. +*/ +bool KAEventData::convertStartOfDay(Event* event, const KTimeZone& timeZone) +{ + bool changed = false; + QTime midnight(0, 0); + QStringList flags = event->customProperty(KCalendar::APPNAME, FLAGS_PROPERTY).split(SC, QString::SkipEmptyParts); + if (flags.indexOf(DATE_ONLY_FLAG) >= 0) + { + // It's an untimed event, so fix it + QTime oldTime = event->dtStart().time(); + int adjustment = oldTime.secsTo(midnight); + if (adjustment) + { + event->setDtStart(KDateTime(event->dtStart().date(), midnight, timeZone)); + Alarm::List alarms = event->alarms(); + int deferralOffset = 0; + for (int ai = 0, aend = alarms.count(); ai < aend; ++ai) + { + // Parse the next alarm's text + Alarm* alarm = alarms[ai]; + AlarmData data; + readAlarm(alarm, data); + if (data.type & KAAlarm::TIMED_DEFERRAL_FLAG) + { + // Timed deferral alarm, so adjust the offset + deferralOffset = alarm->startOffset().asSeconds(); + alarm->setStartOffset(deferralOffset - adjustment); + } + else if (data.type == KAAlarm::AUDIO__ALARM + && alarm->startOffset().asSeconds() == deferralOffset) + { + // Audio alarm is set for the same time as the deferral alarm + alarm->setStartOffset(deferralOffset - adjustment); + } + } + changed = true; + } + } + else + { + // It's a timed event. Fix any untimed alarms. + int deferralOffset = 0; + int newDeferralOffset = 0; + DateTime start; + KDateTime nextMainDateTime = readDateTime(event, false, start).kDateTime(); + AlarmMap alarmMap; + readAlarms(event, &alarmMap); + for (AlarmMap::Iterator it = alarmMap.begin(); it != alarmMap.end(); ++it) + { + const AlarmData& data = it.value(); + if (!data.alarm->hasStartOffset()) + continue; + if ((data.type & KAAlarm::DEFERRED_ALARM) + && !(data.type & KAAlarm::TIMED_DEFERRAL_FLAG)) + { + // Date-only deferral alarm, so adjust its time + KDateTime altime = data.alarm->startOffset().end(nextMainDateTime); + altime.setTime(midnight); + deferralOffset = data.alarm->startOffset().asSeconds(); + newDeferralOffset = event->dtStart().secsTo(altime); + const_cast(data.alarm)->setStartOffset(newDeferralOffset); + changed = true; + } + else if (data.type == KAAlarm::AUDIO__ALARM + && data.alarm->startOffset().asSeconds() == deferralOffset) + { + // Audio alarm is set for the same time as the deferral alarm + const_cast(data.alarm)->setStartOffset(newDeferralOffset); + changed = true; + } + } + } + return changed; +} + #if 0 /****************************************************************************** * If the calendar was written by a pre-1.9.10 version of KAlarm, or another diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/cal/kaeventdata.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/cal/kaeventdata.h --- kde-nightly-kdepim-20091006+svn1032120/kalarm/cal/kaeventdata.h 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/cal/kaeventdata.h 2009-10-09 23:31:00.000000000 +0100 @@ -428,6 +428,7 @@ bool setRecurAnnualByDate(int freq, const QList& months, int day, KARecurrence::Feb29Type, int count, const QDate& end); bool setRecurAnnualByPos(int freq, const QList& pos, const QList& months, int count, const QDate& end); // static QValueList convRecurPos(const QValueList&); + void adjustRecurrenceStartOfDay(); #ifdef NDEBUG void dumpDebug() const { } #else @@ -436,8 +437,7 @@ static QByteArray icalProductId(); static int currentCalendarVersion(); static QByteArray currentCalendarVersionString(); - static bool adjustStartOfDay(const KCal::Event::List&, const QTime& startOfDay, const KTimeZone& timeZone); - static bool convertKCalEvents(KCal::CalendarLocal&, int version, bool adjustSummerTime, const QTime& startOfDay); + static bool convertKCalEvents(KCal::CalendarLocal&, int calendarVersion, bool adjustSummerTime, const QTime& startOfDay, const KTimeZone&); // static bool convertRepetitions(KCal::CalendarLocal&); KARecurrence::Type checkRecur() const; void checkRepetition() const; @@ -455,6 +455,7 @@ void clearRecur(); OccurType nextRecurrence(const KDateTime& preDateTime, DateTime& result, const QTime& startOfDay) const; void notifyChanges() const; + static bool convertStartOfDay(KCal::Event*, const KTimeZone&); static bool convertRepetition(KCal::Event*); KCal::Alarm* initKCalAlarm(KCal::Event*, const DateTime&, const QStringList& types, KAAlarm::Type = KAAlarm::INVALID_ALARM) const; KCal::Alarm* initKCalAlarm(KCal::Event*, int startOffsetSecs, const QStringList& types, KAAlarm::Type = KAAlarm::INVALID_ALARM) const; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/cal/karecurrence.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/cal/karecurrence.cpp --- kde-nightly-kdepim-20091006+svn1032120/kalarm/cal/karecurrence.cpp 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/cal/karecurrence.cpp 2009-10-09 23:31:00.000000000 +0100 @@ -154,7 +154,7 @@ } mFeb29Type = feb29Type; } - setStartDateTime(startdt); // sets recurrence all-day if date-only + Recurrence::setStartDateTime(startdt); // sets recurrence all-day if date-only return true; } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/cal/karecurrence.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/cal/karecurrence.h --- kde-nightly-kdepim-20091006+svn1032120/kalarm/cal/karecurrence.h 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/cal/karecurrence.h 2009-10-09 23:31:00.000000000 +0100 @@ -66,6 +66,8 @@ { return init(t, freq, count, f29, start, end); } void fix(); void writeRecurrence(KCal::Recurrence&) const; + void setStartDateTime(const KDateTime& dt, bool dateOnly) + { KCal::Recurrence::setStartDateTime(dt); if (dateOnly) KCal::Recurrence::setAllDay(true); } KDateTime endDateTime() const; QDate endDate() const; bool recursOn(const QDate&, const KDateTime::Spec&) const; @@ -81,6 +83,9 @@ static void setDefaultFeb29Type(Feb29Type t) { mDefaultFeb29 = t; } private: + /** Prevent public use: KARecurrence::setStartDateTime() handles all-day setting. */ + void setAllDay(bool); + bool set(Type, int freq, int count, int feb29Type, const KDateTime& start, const KDateTime& end); bool init(KCal::RecurrenceRule::PeriodType, int freq, int count, int feb29Type, const KDateTime& start, const KDateTime& end); int combineDurations(const KCal::RecurrenceRule*, const KCal::RecurrenceRule*, QDate& end) const; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/calendarcompat.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/calendarcompat.cpp --- kde-nightly-kdepim-20091006+svn1032120/kalarm/calendarcompat.cpp 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/calendarcompat.cpp 2009-10-09 23:31:00.000000000 +0100 @@ -82,7 +82,7 @@ kDebug() << "KAlarm version" << version; // Convert events to current KAlarm format for if the calendar is saved - KAEventData::convertKCalEvents(calendar, version, version057_UTC, Preferences::startOfDay()); + KAEventData::convertKCalEvents(calendar, version, version057_UTC, Preferences::startOfDay(), Preferences::timeZone()); if (!resource) return KCalendar::Current; // update non-shared calendars regardless if (resource->ResourceCached::readOnly() || conv == AlarmResource::NO_CONVERT) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarmapp.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarmapp.cpp --- kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarmapp.cpp 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarmapp.cpp 2009-10-09 23:31:00.000000000 +0100 @@ -128,7 +128,7 @@ Preferences::self()->readConfig(); Preferences::setAutoStart(true); Preferences::self()->writeConfig(); - Preferences::connect(SIGNAL(startOfDayChanged(const QTime&, const QTime&)), this, SLOT(changeStartOfDay())); + Preferences::connect(SIGNAL(startOfDayChanged(const QTime&)), this, SLOT(changeStartOfDay())); Preferences::connect(SIGNAL(feb29TypeChanged(Feb29Type)), this, SLOT(slotFeb29TypeChanged(Feb29Type))); Preferences::connect(SIGNAL(showInSystemTrayChanged(bool)), this, SLOT(slotShowInSystemTrayChanged())); Preferences::connect(SIGNAL(archivedKeepDaysChanged(int)), this, SLOT(setArchivePurgeDays())); @@ -143,10 +143,7 @@ KConfigGroup config(KGlobal::config(), "General"); mNoSystemTray = config.readEntry("NoSystemTray", false); mOldShowInSystemTray = wantShowInSystemTray(); - mStartOfDay = Preferences::startOfDay(); - if (Preferences::hasStartOfDayChanged()) - mStartOfDay.setHMS(100,0,0); // start of day time has changed: flag it as invalid - DateTime::setStartOfDay(mStartOfDay); + DateTime::setStartOfDay(Preferences::startOfDay()); mPrefsArchivedColour = Preferences::archivedColour(); } @@ -830,13 +827,8 @@ */ void KAlarmApp::changeStartOfDay() { - QTime sod = Preferences::startOfDay(); - DateTime::setStartOfDay(sod); - AlarmCalendar* cal = AlarmCalendar::resources(); - if (KAEventData::adjustStartOfDay(cal->kcalEvents(KCalEvent::ACTIVE), Preferences::startOfDay(), Preferences::timeZone())) - cal->save(); - Preferences::updateStartOfDayCheck(sod); // now that calendar is updated, set OK flag in config file - mStartOfDay = sod; + DateTime::setStartOfDay(Preferences::startOfDay()); + AlarmCalendar::resources()->adjustStartOfDay(); } /****************************************************************************** @@ -1851,8 +1843,6 @@ if (firstTime) { kDebug() << "first time"; - if (!mStartOfDay.isValid()) - changeStartOfDay(); // start of day time has changed, so adjust date-only alarms /* Need to open the display calendar now, since otherwise if display * alarms are immediately due, they will often be processed while diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarmapp.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarmapp.h --- kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarmapp.h 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarmapp.h 2009-10-09 23:31:00.000000000 +0100 @@ -173,7 +173,6 @@ DBusHandler* mDBusHandler; // the parent of the main DCOP receiver object TrayWindow* mTrayWindow; // active system tray icon QTimer* mAlarmTimer; // activates KAlarm when next alarm is due - QTime mStartOfDay; // start-of-day time currently in use QColor mPrefsArchivedColour; // archived alarms text colour int mArchivedPurgeDays; // how long to keep archived alarms, 0 = don't keep, -1 = keep indefinitely int mPurgeDaysQueued; // >= 0 to purge the archive calendar from KAlarmApp::processLoop() diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarmconfig.kcfg /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarmconfig.kcfg --- kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarmconfig.kcfg 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarmconfig.kcfg 2009-10-09 23:31:00.000000000 +0100 @@ -175,11 +175,6 @@ QDateTime(QDate(1900,1,1),QTime(0,0)) - The start time of the working day. diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarm.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarm.h --- kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarm.h 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarm.h 2009-10-09 23:31:00.000000000 +0100 @@ -23,7 +23,7 @@ #undef QT3_SUPPORT -#define KALARM_VERSION "2.2.90" +#define KALARM_VERSION "2.3.2" #define KALARM_NAME "KAlarm" #define KALARM_DBUS_SERVICE "org.kde.kalarm" // D-Bus service name of KAlarm application diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarm.upd /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarm.upd --- kde-nightly-kdepim-20091006+svn1032120/kalarm/kalarm.upd 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/kalarm.upd 2009-10-09 23:31:00.000000000 +0100 @@ -63,9 +63,17 @@ Options=overwrite Script=kalarm-2.0.2-general.pl +# KAlarm version 2.1.5 # Convert KDE3 konsole -T command parameter Id=2.1.5 File=kalarmrc Group=General Options=overwrite Script=kalarm-2.1.5-general.pl + +# KAlarm version 2.3.2 +# Remove obsolete key +Id=2.3.2 +File=kalarmrc +Group=General +RemoveKey=Sod diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/lib/datetime.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/lib/datetime.cpp --- kde-nightly-kdepim-20091006+svn1032120/kalarm/lib/datetime.cpp 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/lib/datetime.cpp 2009-10-09 23:31:00.000000000 +0100 @@ -1,7 +1,7 @@ /* * datetime.cpp - date/time with start-of-day time for date-only values * Program: kalarm - * Copyright © 2003,2005-2007 by David Jarvie + * Copyright © 2003,2005-2007,2009 by David Jarvie * * 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 @@ -53,6 +53,17 @@ return mDateTime; } +KDateTime DateTime::calendarKDateTime() const +{ + if (mDateTime.isDateOnly()) + { + KDateTime dt = mDateTime; + dt.setTime(QTime(0, 0)); + return dt; + } + return mDateTime; +} + QString DateTime::formatLocale(bool shortFormat) const { return KGlobal::locale()->formatDateTime(mDateTime, (shortFormat ? KLocale::ShortDate : KLocale::LongDate)); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/lib/datetime.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/lib/datetime.h --- kde-nightly-kdepim-20091006+svn1032120/kalarm/lib/datetime.h 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/lib/datetime.h 2009-10-09 23:31:00.000000000 +0100 @@ -1,7 +1,7 @@ /* * datetime.h - date/time with start-of-day time for date-only values * Program: kalarm - * Copyright © 2003,2005-2007 by David Jarvie + * Copyright © 2003,2005-2007,2009 by David Jarvie * * 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 @@ -31,7 +31,7 @@ * DateTime is very similar to the KDateTime class. The time assumed for date-only values * is the start-of-day time set by setStartOfDay(). * - * @author David Jarvie + * @author David Jarvie */ class DateTime { @@ -83,6 +83,10 @@ * by setStartOfDay(). */ KDateTime effectiveKDateTime() const; + /** Returns the date and time of the value as written in the calendar. + * If the value is date-only, the time part returned is 00:00. + */ + KDateTime calendarKDateTime() const; /** Returns the time zone of the value. */ KTimeZone timeZone() const { return mDateTime.timeZone(); } /** Returns the time specification of the value. */ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/preferences.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/preferences.cpp --- kde-nightly-kdepim-20091006+svn1032120/kalarm/preferences.cpp 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/preferences.cpp 2009-10-09 23:31:00.000000000 +0100 @@ -68,8 +68,6 @@ bool Preferences::mUsingDefaults = false; KTimeZone Preferences::mSystemTimeZone; HolidayRegion* Preferences::mHolidays = 0; // always non-null after Preferences initialisation -QTime Preferences::mOldStartOfDay(0, 0, 0); -bool Preferences::mStartOfDayChanged = false; Preferences* Preferences::self() @@ -151,47 +149,19 @@ emit mInstance->holidaysChanged(holidays()); } -static const int SODxor = 0x82451630; -inline int Preferences::startOfDayCheck(const QTime& t) -{ - // Combine with a 'random' constant to prevent 'clever' people fiddling the - // value, and thereby screwing things up. - return QTime().msecsTo(t) ^ SODxor; -} - void Preferences::setStartOfDay(const QTime& t) { - self()->setBase_StartOfDay(QDateTime(QDate(1900,1,1), t)); - // Combine with a 'random' constant to prevent 'clever' people fiddling the - // value, and thereby screwing things up. - updateStartOfDayCheck(t); - if (t != mOldStartOfDay) + if (t != self()->mBase_StartOfDay.time()) { - emit mInstance->startOfDayChanged(t, mOldStartOfDay); - mOldStartOfDay = t; + self()->setBase_StartOfDay(QDateTime(QDate(1900,1,1), t)); + emit mInstance->startOfDayChanged(t); } } // Called when the start of day value has changed in the config file void Preferences::startDayChange(const QDateTime& dt) { - int SOD = sod(); - if (SOD) - mOldStartOfDay = QTime(0,0).addMSecs(SOD ^ SODxor); - QTime t = dt.time(); - mStartOfDayChanged = (t != mOldStartOfDay); - if (mStartOfDayChanged) - { - emit mInstance->startOfDayChanged(t, mOldStartOfDay); - mOldStartOfDay = t; - } -} - -void Preferences::updateStartOfDayCheck(const QTime& t) -{ - self()->setSod(startOfDayCheck(t)); - self()->writeConfig(); - mStartOfDayChanged = false; + emit mInstance->startOfDayChanged(dt.time()); } QBitArray Preferences::workDays() diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/preferences.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/preferences.h --- kde-nightly-kdepim-20091006+svn1032120/kalarm/preferences.h 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/preferences.h 2009-10-09 23:31:00.000000000 +0100 @@ -48,8 +48,6 @@ static void setHolidayRegion(const QString& regionCode); static QTime startOfDay() { return self()->mBase_StartOfDay.time(); } static void setStartOfDay(const QTime&); - static void updateStartOfDayCheck(const QTime&); - static bool hasStartOfDayChanged() { return mStartOfDayChanged; } static QTime workDayStart() { return self()->mBase_WorkDayStart.time(); } static QTime workDayEnd() { return self()->mBase_WorkDayEnd.time(); } static QBitArray workDays(); @@ -86,7 +84,7 @@ signals: void timeZoneChanged(const KTimeZone& newTz); void holidaysChanged(const KHolidays::HolidayRegion& newHolidays); - void startOfDayChanged(const QTime& newStartOfDay, const QTime& oldStartOfDay); + void startOfDayChanged(const QTime& newStartOfDay); void workTimeChanged(const QTime& startTime, const QTime& endTime, const QBitArray& workDays); private slots: @@ -108,8 +106,6 @@ // All the following members are accessed by the Preferences dialog classes static int mMessageButtonDelay; // 0 = scatter; -1 = no delay, no scatter; >0 = delay, no scatter - static QTime mOldStartOfDay; // previous start-of-day time - static bool mStartOfDayChanged; // start-of-day check value doesn't tally with new StartOfDay }; #endif // PREFERENCES_H diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/startdaytimer.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/startdaytimer.cpp --- kde-nightly-kdepim-20091006+svn1032120/kalarm/startdaytimer.cpp 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/startdaytimer.cpp 2009-10-09 23:31:00.000000000 +0100 @@ -1,7 +1,7 @@ /* * startdaytimer.cpp - timer triggered at the user-defined start-of-day time * Program: kalarm - * Copyright (C) 2004, 2005 by David Jarvie + * Copyright © 2004,2005,2009 by David Jarvie * * 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 @@ -29,7 +29,7 @@ StartOfDayTimer::StartOfDayTimer() : DailyTimer(Preferences::startOfDay(), false) { - Preferences::connect(SIGNAL(startOfDayChanged(const QTime&, const QTime&)), this, SLOT(startOfDayChanged(const QTime&, const QTime&))); + Preferences::connect(SIGNAL(startOfDayChanged(const QTime&)), this, SLOT(startOfDayChanged())); } StartOfDayTimer* StartOfDayTimer::instance() @@ -43,7 +43,7 @@ * Called when the start-of-day time has changed. * The timer is adjusted and if appropriate timer events are triggered now. */ -void StartOfDayTimer::startOfDayChanged(const QTime&, const QTime&) +void StartOfDayTimer::startOfDayChanged() { changeTime(Preferences::startOfDay(), true); } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kalarm/startdaytimer.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kalarm/startdaytimer.h --- kde-nightly-kdepim-20091006+svn1032120/kalarm/startdaytimer.h 2009-10-06 23:28:06.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kalarm/startdaytimer.h 2009-10-09 23:31:00.000000000 +0100 @@ -1,7 +1,7 @@ /* * startdaytimer.h - timer triggered at the user-defined start-of-day time * Program: kalarm - * Copyright © 2004,2005 by David Jarvie + * Copyright © 2004,2005,2009 by David Jarvie * * 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 @@ -30,7 +30,7 @@ * start-of-day time (set in KAlarm's Preferences dialog). * It automatically adjusts to any changes in the start-of-day time. * - * @author David Jarvie + * @author David Jarvie */ class StartOfDayTimer : public DailyTimer { @@ -56,7 +56,7 @@ static StartOfDayTimer* instance(); private slots: - void startOfDayChanged(const QTime& newStartOfDay, const QTime& oldStartOfDay); + void startOfDayChanged(); private: static StartOfDayTimer* mInstance; // exists solely to receive signals diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kleopatra/aboutdata.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kleopatra/aboutdata.cpp --- kde-nightly-kdepim-20091006+svn1032120/kleopatra/aboutdata.cpp 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kleopatra/aboutdata.cpp 2009-10-09 23:31:06.000000000 +0100 @@ -35,14 +35,20 @@ #include "aboutdata.h" +#include + #include #include #include #include +#include +#include #include +using namespace Kleo; + static const char kleopatra_version[] = KLEOPATRA_VERSION_STRING; static const char description[] = I18N_NOOP("Certificate Manager and Unified Crypto GUI"); @@ -101,7 +107,25 @@ "Both relevant cryptography standards are supported, OpenPGP " "and S/MIME. Gpg4win and the software included with Gpg4win " "are Free Software."); -static const char gpg4win_version[] = "2.0.0"; // ### make this better come from somewhere... + +static const char gpg4win_version_guessed[] = "2.0.1"; + +static QString gpg4win_version() { + + QProcess p; + p.setReadChannelMode( QProcess::MergedChannels ); + p.start( gpgConfPath(), QStringList( QLatin1String( "--version" ) ) ); + if ( !p.waitForFinished() ) + return QString::fromLatin1( "%1 (%2)" ).arg( QLatin1String( gpg4win_version_guessed ), + i18nc("Version string is a guess","guessed") ); + const QString output = QTextStream( &p ).readAll() ; + QRegExp rx( QLatin1String( "\\(Gpg4win\\s+([^\\s)])+\\)" ) ); + if ( rx.indexIn( output ) != -1 ) + return rx.cap(1); + else + return QString::fromLatin1( "%1 (%2)" ).arg( QLatin1String( gpg4win_version_guessed ), + i18nc("Version string is a guess","guessed") ); +} static QPixmap UserIcon_nocached2( const char * name ) { @@ -117,7 +141,7 @@ AboutGpg4WinData::AboutGpg4WinData() : KAboutData( "gpg4win", 0, ki18n("Gpg4win"), - gpg4win_version, ki18n(gpg4win_description), + gpg4win_version().toLatin1(), ki18n(gpg4win_description), License_GPL, KLocalizedString(), KLocalizedString(), "http://www.gpg4win.de" ) { addAuthor( ki18n("Intevation GmbH (Project Management)"), KLocalizedString(), 0, "http://www.intevation.de" ); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kleopatra/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kleopatra/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/kleopatra/CMakeLists.txt 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kleopatra/CMakeLists.txt 2009-10-09 23:31:06.000000000 +0100 @@ -2,7 +2,7 @@ include(MacroOptionalAddSubdirectory) -set( kleopatra_version 2.0.11 ) +set( kleopatra_version 2.0.12 ) set( kleopatra_release FALSE ) if (NOT kleopatra_release) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kleopatra/commands/adduseridcommand.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kleopatra/commands/adduseridcommand.h --- kde-nightly-kdepim-20091006+svn1032120/kleopatra/commands/adduseridcommand.h 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kleopatra/commands/adduseridcommand.h 2009-10-09 23:31:06.000000000 +0100 @@ -46,7 +46,7 @@ explicit AddUserIDCommand( const GpgME::Key & key ); ~AddUserIDCommand(); - /* reimp */ static Restrictions restrictions() { return OnlyOneKey|MustBeOpenPGP; } + /* reimp */ static Restrictions restrictions() { return OnlyOneKey|MustBeOpenPGP|NeedSecretKey; } void setName( const QString & name ); const QString & name() const; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kleopatra/commands/learncardkeyscommand.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kleopatra/commands/learncardkeyscommand.cpp --- kde-nightly-kdepim-20091006+svn1032120/kleopatra/commands/learncardkeyscommand.cpp 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kleopatra/commands/learncardkeyscommand.cpp 2009-10-09 23:31:06.000000000 +0100 @@ -63,7 +63,7 @@ QStringList LearnCardKeysCommand::arguments() const { if ( protocol() == OpenPGP ) - return QStringList() << gpgPath() << "--learn-card" << "-v"; + return QStringList() << gpgPath() << "--batch" << "--card-status" << "-v"; else return QStringList() << gpgSmPath() << "--learn-card" << "-v"; } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kleopatra/mainwindow.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kleopatra/mainwindow.cpp --- kde-nightly-kdepim-20091006+svn1032120/kleopatra/mainwindow.cpp 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kleopatra/mainwindow.cpp 2009-10-09 23:31:06.000000000 +0100 @@ -292,7 +292,7 @@ } void aboutGpg4Win() { - ( new KAboutApplicationDialog( aboutGpg4WinData(), q ) )->show(); + ( new KAboutApplicationDialog( aboutGpg4WinData(), KAboutApplicationDialog::HideKdeVersion|KAboutApplicationDialog::HideTranslators, q ) )->show(); } private: @@ -458,8 +458,10 @@ // Window menu // (come from ui.tabWidget) // Help menu +#ifdef Q_WS_WIN { "help_about_gpg4win", i18n("About Gpg4win"), QString(), "gpg4win-compact", q, SLOT(aboutGpg4Win()), QString(), false, true }, +#endif }; make_actions_from_data( action_data, /*sizeof action_data / sizeof *action_data,*/ coll ); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kleopatra/newcertificatewizard/advancedsettingsdialog.ui /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kleopatra/newcertificatewizard/advancedsettingsdialog.ui --- kde-nightly-kdepim-20091006+svn1032120/kleopatra/newcertificatewizard/advancedsettingsdialog.ui 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kleopatra/newcertificatewizard/advancedsettingsdialog.ui 2009-10-09 23:31:06.000000000 +0100 @@ -133,7 +133,7 @@ true - + ElGamal + + Elgamal diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kleopatra/systrayicon.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kleopatra/systrayicon.cpp --- kde-nightly-kdepim-20091006+svn1032120/kleopatra/systrayicon.cpp 2009-10-06 23:28:11.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kleopatra/systrayicon.cpp 2009-10-09 23:31:06.000000000 +0100 @@ -102,6 +102,7 @@ decryptVerifyClipboardAction.setEnabled( DecryptVerifyClipboardCommand::canDecryptVerifyCurrentClipboard() ); setInitialPinAction.setEnabled( anyCardHasNullPin ); learnCertificatesAction.setEnabled( anyCardCanLearnKeys ); + cardMenu.setEnabled( anyCardHasNullPin || anyCardCanLearnKeys ); q->setAttentionWanted( ( anyCardHasNullPin || anyCardCanLearnKeys ) && !q->attentionWindow() ); } @@ -202,8 +203,8 @@ openPGPSignClipboardAction( i18n("OpenPGP-Sign..."), q ), decryptVerifyClipboardAction( i18n("Decrypt/Verify..."), q ), cardMenu( i18n("SmartCard") ), - setInitialPinAction( i18n("Set Initial PIN..."), q ), - learnCertificatesAction( i18n("Learn Card Certificates"), q ), + setInitialPinAction( i18n("Set NetKey v3 Initial PIN..."), q ), + learnCertificatesAction( i18n("Learn NetKey v3 Card Certificates"), q ), aboutDialog(), mainWindowPreviousGeometry() { diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/kmail/CMakeLists.txt 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/CMakeLists.txt 2009-10-09 23:30:58.000000000 +0100 @@ -342,6 +342,7 @@ ${KDE4_KHTML_LIBRARY} ${KDE4_THREADWEAVER_LIBRARY} ${KDE4_KMIME_LIBRARY} + messagecore messagelist ${KDEPIMLIBS_KPIMIDENTITIES_LIBRARY} ${KDEPIMLIBS_KONTACTINTERFACE_LIBS} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/folderselectiontreewidget.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/folderselectiontreewidget.h --- kde-nightly-kdepim-20091006+svn1032120/kmail/folderselectiontreewidget.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/folderselectiontreewidget.h 2009-10-09 23:30:58.000000000 +0100 @@ -68,7 +68,7 @@ * Reload the tree and select which folders to show and which not * * @param mustBeReadWrite If true, the read-only folders become non selectable - * @param showOutbox If trye, the otbox folder is shown + * @param showOutbox If true, the outbox folder is shown * @param showImapFolders Whether to show the IMAP folder hierarchy * @param preSelection The initial folder to select */ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/headerstyle.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/headerstyle.cpp --- kde-nightly-kdepim-20091006+svn1032120/kmail/headerstyle.cpp 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/headerstyle.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -379,12 +379,22 @@ } QString titleText; - QString confidenceString; - if ( spamError == noError ) { - confidenceString = ( confidence >= 0 ? QString::number( confidence ) + "% " : QString() ) + " "; - titleText = i18n("%1% probability of being spam with confidence %3%.\n\n" - "Full report:\nProbability=%2\nConfidence=%4", - percent, filterHeader, confidence, confidenceHeader ); + QString confidenceString = QString(); + if ( spamError == noError ) + { + if ( confidence >= 0 ) + { + confidenceString = QString::number( confidence ) + "%  "; + titleText = i18n("%1% probability of being spam with confidence %3%.\n\n" + "Full report:\nProbability=%2\nConfidence=%4", + percent, filterHeader, confidence, confidenceHeader ); + } + else // do not show negative confidence + { + titleText = i18n("%1% probability of being spam.\n\n" + "Full report:\nProbability=%2", + percent, filterHeader); + } } else { diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/isubject.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/isubject.cpp --- kde-nightly-kdepim-20091006+svn1032120/kmail/isubject.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/isubject.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -25,14 +25,14 @@ void ISubject::notify() { - for ( QVector::iterator it = mObserverList.begin() ; it != mObserverList.end() ; ++it ) - { - if ( (*it) ) - { + // iterate over a copy (to prevent crashes when + // {attach(),detach()} is called from an Observer::update() + const QVector copy = mObserverList; + for ( QVector::const_iterator it = copy.begin() ; it != copy.end() ; ++it ) { + if ( (*it) ) { (*it)->update( this ); } } } - } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/KMail.desktop /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/KMail.desktop --- kde-nightly-kdepim-20091006+svn1032120/kmail/KMail.desktop 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/KMail.desktop 2009-10-09 23:30:58.000000000 +0100 @@ -135,5 +135,5 @@ X-KDE-StartupNotify=true X-DBUS-StartupType=Unique X-DBUS-ServiceName=org.kde.kmail -X-KDE-ServiceTypes=DBUS/ResourceBackend/IMAP,DBUS/Mailer +X-KDE-ServiceTypes=DBUS/Mailer Categories=Qt;KDE;Network;Email; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/kmcommands.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/kmcommands.h --- kde-nightly-kdepim-20091006+svn1032120/kmail/kmcommands.h 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/kmcommands.h 2009-10-09 23:30:58.000000000 +0100 @@ -7,7 +7,7 @@ #include "kmmsgbase.h" #include -#include +#include using KPIM::MessageStatus; #include #include diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/kmmsgbase.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/kmmsgbase.h --- kde-nightly-kdepim-20091006+svn1032120/kmail/kmmsgbase.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/kmmsgbase.h 2009-10-09 23:30:58.000000000 +0100 @@ -20,7 +20,7 @@ #ifndef kmmsgbase_h #define kmmsgbase_h -#include "messagestatus.h" +#include using KPIM::MessageStatus; // for large file support flags diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/kmreaderwin.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/kmreaderwin.cpp --- kde-nightly-kdepim-20091006+svn1032120/kmail/kmreaderwin.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/kmreaderwin.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -176,81 +176,33 @@ kDebug() << "-------------------------------------------------"; kDebug() << "START" << "(" << recCount << ")"; if( node ) { + + kDebug(5006) << node->typeString() << '/' << node->subTypeString(); + partNode* curNode = node; partNode* dataNode = curNode; partNode * child = node->firstChild(); - bool bIsMultipart = false; + const bool bIsMultipart = node->type() == DwMime::kTypeMultipart; + bool bKeepPartAsIs = false; - switch( curNode->type() ){ - case DwMime::kTypeText: { - kDebug() << "* text *"; - switch( curNode->subType() ){ - case DwMime::kSubtypeHtml: - kDebug() << "html"; - break; - case DwMime::kSubtypeXVCard: - kDebug() << "v-card"; - break; - case DwMime::kSubtypeRichtext: - kDebug() << "rich text"; - break; - case DwMime::kSubtypeEnriched: - kDebug() << "enriched"; - break; - case DwMime::kSubtypePlain: - kDebug() << "plain"; - break; - default: - kDebug() << "default"; - break; - } - } - break; + switch( curNode->type() ) { case DwMime::kTypeMultipart: { - kDebug() << "* multipart *"; - bIsMultipart = true; - switch( curNode->subType() ){ - case DwMime::kSubtypeMixed: - kDebug() << "mixed"; - break; - case DwMime::kSubtypeAlternative: - kDebug() << "alternative"; - break; - case DwMime::kSubtypeDigest: - kDebug() << "digest"; - break; - case DwMime::kSubtypeParallel: - kDebug() << "parallel"; - break; - case DwMime::kSubtypeSigned: - kDebug() << "signed"; + switch( curNode->subType() ) { + case DwMime::kSubtypeSigned: { + bKeepPartAsIs = true; + } break; case DwMime::kSubtypeEncrypted: { - kDebug() << "encrypted"; - if ( child ) { - /* - ATTENTION: This code is to be replaced by the new 'auto-detect' feature. -------------------------------------- - */ - partNode* data = - child->findType( DwMime::kTypeApplication, DwMime::kSubtypeOctetStream, false, true ); - if ( !data ) - data = child->findType( DwMime::kTypeApplication, DwMime::kSubtypePkcs7Mime, false, true ); - if ( data && data->firstChild() ) - dataNode = data; - } + if ( child ) + dataNode = child; } break; - default : - kDebug() << "( unknown subtype )"; - break; } } break; case DwMime::kTypeMessage: { - kDebug() << "* message *"; - switch( curNode->subType() ){ + switch( curNode->subType() ) { case DwMime::kSubtypeRfc822: { - kDebug() << "RfC 822"; if ( child ) dataNode = child; } @@ -259,25 +211,19 @@ } break; case DwMime::kTypeApplication: { - kDebug() << "* application *"; - switch( curNode->subType() ){ - case DwMime::kSubtypePostscript: - kDebug() << "postscript"; - break; + switch( curNode->subType() ) { case DwMime::kSubtypeOctetStream: { - kDebug() << "octet stream"; if ( child ) dataNode = child; } break; - case DwMime::kSubtypePgpEncrypted: - kDebug() << "pgp encrypted"; - break; - case DwMime::kSubtypePgpSignature: - kDebug() << "pgp signed"; + case DwMime::kSubtypePkcs7Signature: { + // note: subtype Pkcs7Signature specifies a signature part + // which we do NOT want to remove! + bKeepPartAsIs = true; + } break; case DwMime::kSubtypePkcs7Mime: { - kDebug() << "pkcs7 mime"; // note: subtype Pkcs7Mime can also be signed // and we do NOT want to remove the signature! if ( child && curNode->encryptionState() != KMMsgNotEncrypted ) @@ -287,39 +233,6 @@ } } break; - case DwMime::kTypeImage: { - kDebug() << "* image *"; - switch( curNode->subType() ){ - case DwMime::kSubtypeJpeg: - kDebug() << "JPEG"; - break; - case DwMime::kSubtypeGif: - kDebug() << "GIF"; - break; - } - } - break; - case DwMime::kTypeAudio: { - kDebug() << "* audio *"; - switch( curNode->subType() ){ - case DwMime::kSubtypeBasic: - kDebug() << "basic"; - break; - } - } - break; - case DwMime::kTypeVideo: { - kDebug() << "* video *"; - switch( curNode->subType() ){ - case DwMime::kSubtypeMpeg: - kDebug() << "mpeg"; - break; - } - } - break; - case DwMime::kTypeModel: - kDebug() << "* model *"; - break; } @@ -357,40 +270,45 @@ } } - // B) Store the body of this part. - if( headers && bIsMultipart && dataNode->firstChild() ) { - kDebug() << "is valid Multipart, processing children:"; - QByteArray boundary = headers->ContentType().Boundary().c_str(); - curNode = dataNode->firstChild(); - // store children of multipart - while( curNode ) { - kDebug() << "--boundary"; - if( resultingData.size() && - ( '\n' != resultingData.at( resultingData.size()-1 ) ) ) + if ( bKeepPartAsIs ) { + resultingData += dataNode->encodedBody(); + } else { + + // B) Store the body of this part. + if( headers && bIsMultipart && dataNode->firstChild() ) { + kDebug() << "is valid Multipart, processing children:"; + QByteArray boundary = headers->ContentType().Boundary().c_str(); + curNode = dataNode->firstChild(); + // store children of multipart + while( curNode ) { + kDebug() << "--boundary"; + if( resultingData.size() && + ( '\n' != resultingData.at( resultingData.size()-1 ) ) ) + resultingData += '\n'; + resultingData += '\n'; + resultingData += "--"; + resultingData += boundary; resultingData += '\n'; - resultingData += '\n'; - resultingData += "--"; + // note: We are processing a harmless multipart that is *not* + // to be replaced by one of it's children, therefor + // we set their doStoreHeaders to true. + objectTreeToDecryptedMsg( curNode, + resultingData, + theMessage, + false, + recCount + 1 ); + curNode = curNode->nextSibling(); + } + kDebug() << "--boundary--"; + resultingData += "\n--"; resultingData += boundary; - resultingData += '\n'; - // note: We are processing a harmless multipart that is *not* - // to be replaced by one of it's children, therefor - // we set their doStoreHeaders to true. - objectTreeToDecryptedMsg( curNode, - resultingData, - theMessage, - false, - recCount + 1 ); - curNode = curNode->nextSibling(); + resultingData += "--\n\n"; + kDebug() << "Multipart processing children - DONE"; + } else if( part ){ + // store simple part + kDebug() << "is Simple part or invalid Multipart, storing body data .. DONE"; + resultingData += part->Body().AsString().c_str(); } - kDebug() << "--boundary--"; - resultingData += "\n--"; - resultingData += boundary; - resultingData += "--\n\n"; - kDebug() << "Multipart processing children - DONE"; - } else if( part ){ - // store simple part - kDebug() << "is Simple part or invalid Multipart, storing body data .. DONE"; - resultingData += part->Body().AsString().c_str(); } } else { kDebug() << "dataNode != curNode: Replace curNode by dataNode."; @@ -530,7 +448,6 @@ mLastSerNum = 0; mWaitingForSerNum = 0; mMessage = 0; - mLastStatus.clear(); mMsgDisplay = true; mPrinting = false; mAtmUpdate = false; @@ -1333,14 +1250,11 @@ if (aMsg) { aMsg->setOverrideCodec( overrideCodec() ); aMsg->setDecodeHTML( htmlMail() ); - mLastStatus = aMsg->status(); // FIXME: workaround to disable DND for IMAP load-on-demand if ( !aMsg->isComplete() ) mViewer->setDNDEnabled( false ); else mViewer->setDNDEnabled( true ); - } else { - mLastStatus.clear(); } // only display the msg if it is complete @@ -1621,6 +1535,13 @@ QTimer::singleShot( 1, this, SLOT(injectAttachments()) ); } +static bool message_was_saved_decrypted_before( const KMMessage * msg ) +{ + if ( !msg ) + return false; + kDebug() << "msgId =" << msg->msgId(); + return msg->msgId().trimmed().startsWith( " All received encrypted messages *must* be stored in unencrypted form - // after they have been decrypted once the user has read them. - // ( "Aufhebung der Verschluesselung nach dem Lesen" ) - // - // note: Since there is no configuration option for this, we do that for - // all kinds of encryption now - *not* just for S/MIME. - // This could be changed in the objectTreeToDecryptedMsg() function - // by deciding when (or when not, resp.) to set the 'dataNode' to - // something different than 'curNode'. + // Hack to make sure the S/MIME CryptPlugs follows the strict requirement + // of german government: + // --> All received encrypted messages *must* be stored in unencrypted form + // after they have been decrypted once the user has read them. + // ( "Aufhebung der Verschluesselung nach dem Lesen" ) + // + // note: Since there is no configuration option for this, we do that for + // all kinds of encryption now - *not* just for S/MIME. + // This could be changed in the objectTreeToDecryptedMsg() function + // by deciding when (or when not, resp.) to set the 'dataNode' to + // something different than 'curNode'. -kDebug() << "\n\n\nSpecial post-encryption handling:\n1."; -kDebug() << "(aMsg == msg) =" << (aMsg == message()); -kDebug() << " mLastStatus.isOfUnknownStatus() =" << mLastStatus.isOfUnknownStatus(); -kDebug() << "|| mLastStatus.isNew() =" << mLastStatus.isNew(); -kDebug() << "|| mLastStatus.isUnread) =" << mLastStatus.isUnread(); -kDebug() << "(mIdOfLastViewedMessage != aMsg->msgId()) =" << (mIdOfLastViewedMessage != aMsg->msgId()); -kDebug() << " (KMMsgFullyEncrypted == encryptionState) =" << (KMMsgFullyEncrypted == encryptionState); -kDebug() << "|| (KMMsgPartiallyEncrypted == encryptionState) =" << (KMMsgPartiallyEncrypted == encryptionState); + kDebug() << "\n\n\nSpecial post-encryption handling:\n1."; + kDebug() << "(aMsg == msg) =" << (aMsg == message()); + kDebug() << "aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() = " << (aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder()); + kDebug() << "message_was_saved_decrypted_before( aMsg ) = " << message_was_saved_decrypted_before( aMsg ); + kDebug() << "this->decryptMessage() = " << decryptMessage(); + kDebug() << "otp.hasPendingAsyncJobs() = " << otp.hasPendingAsyncJobs(); + kDebug() << " (KMMsgFullyEncrypted == encryptionState) = " << (KMMsgFullyEncrypted == encryptionState); + kDebug() <<"|| (KMMsgPartiallyEncrypted == encryptionState) =" << (KMMsgPartiallyEncrypted == encryptionState); // only proceed if we were called the normal way - not by // double click on the message (==not running in a separate window) - if( (aMsg == message()) - // only proceed if this message was not saved encryptedly before - // to make sure only *new* messages are saved in decrypted form - && ( mLastStatus.isOfUnknownStatus() - || mLastStatus.isNew() - || mLastStatus.isUnread() ) - // avoid endless recursions - && (mIdOfLastViewedMessage != aMsg->msgId()) - // only proceed if this message is (at least partially) encrypted - && ( (KMMsgFullyEncrypted == encryptionState) - || (KMMsgPartiallyEncrypted == encryptionState) ) ) { - - kDebug() << "Calling objectTreeToDecryptedMsg()"; - - QByteArray decryptedData; - // note: The following call may change the message's headers. - objectTreeToDecryptedMsg( mRootNode, decryptedData, *aMsg ); - kDebug() << "Resulting data:" << decryptedData; - - if( !decryptedData.isEmpty() ) { - kDebug() << "Composing unencrypted message"; - // try this: - aMsg->setBody( decryptedData ); - KMMessage* unencryptedMessage = new KMMessage( *aMsg ); - unencryptedMessage->setParent( 0 ); - // because this did not work: - /* - DwMessage dwMsg( DwString( aMsg->asString() ) ); - dwMsg.Body() = DwBody( DwString( resultString.data() ) ); - dwMsg.Body().Parse(); - KMMessage* unencryptedMessage = new KMMessage( &dwMsg ); - */ - kDebug() << "Resulting message:" << unencryptedMessage->asString(); - kDebug() << "Attach unencrypted message to aMsg"; - aMsg->setUnencryptedMsg( unencryptedMessage ); - emitReplaceMsgByUnencryptedVersion = true; + if( (aMsg == message()) + // don't remove encryption in the outbox folder :) + && ( aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() ) + // only proceed if this message was not saved encryptedly before + && !message_was_saved_decrypted_before( aMsg ) + // only proceed if the message has actually been decrypted + && decryptMessage() + // only proceed if no pending async jobs are running: + && !otp.hasPendingAsyncJobs() + // only proceed if this message is (at least partially) encrypted + && ( (KMMsgFullyEncrypted == encryptionState) + || (KMMsgPartiallyEncrypted == encryptionState) ) ) { + + kDebug() << "Calling objectTreeToDecryptedMsg()"; + + QByteArray decryptedData; + // note: The following call may change the message's headers. + objectTreeToDecryptedMsg( mRootNode, decryptedData, *aMsg ); + kDebug() << "Resulting data:" << decryptedData; + + if( !decryptedData.isEmpty() ) { + kDebug() << "Composing unencrypted message"; + // try this: + aMsg->setBody( decryptedData ); + KMMessage* unencryptedMessage = new KMMessage( *aMsg ); + unencryptedMessage->setParent( 0 ); + // because this did not work: + /* + DwMessage dwMsg( DwString( aMsg->asString() ) ); + dwMsg.Body() = DwBody( DwString( resultString.data() ) ); + dwMsg.Body().Parse(); + KMMessage* unencryptedMessage = new KMMessage( &dwMsg ); + */ + kDebug() << "Resulting message:" << unencryptedMessage->asString(); + kDebug() << "Attach unencrypted message to aMsg"; + aMsg->setUnencryptedMsg( unencryptedMessage ); + emitReplaceMsgByUnencryptedVersion = true; + } } } - } // store message id to avoid endless recursions setIdOfLastViewedMessage( aMsg->msgId() ); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/kmreaderwin.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/kmreaderwin.h --- kde-nightly-kdepim-20091006+svn1032120/kmail/kmreaderwin.h 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/kmreaderwin.h 2009-10-09 23:30:58.000000000 +0100 @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include using KPIM::MessageStatus; #include "kmmimeparttree.h" // Needed for friend declaration. @@ -606,7 +606,6 @@ bool mMsgDisplay; bool mNoMDNsWhenEncrypted; unsigned long mLastSerNum; - MessageStatus mLastStatus; KMail::CSSHelper * mCSSHelper; bool mUseFixedFont; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/kmsearchpattern.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/kmsearchpattern.h --- kde-nightly-kdepim-20091006+svn1032120/kmail/kmsearchpattern.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/kmsearchpattern.h 2009-10-09 23:30:58.000000000 +0100 @@ -21,7 +21,7 @@ #define _kmsearchpattern_h_ #include -#include +#include using KPIM::MessageStatus; #include diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/messagelistview/pane.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/messagelistview/pane.cpp --- kde-nightly-kdepim-20091006+svn1032120/kmail/messagelistview/pane.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/messagelistview/pane.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -36,7 +36,8 @@ #include #include -#include +#include +#include #include "globalsettings.h" #include "kmfolder.h" @@ -451,6 +452,10 @@ connect( KMKernel::self()->msgTagMgr(), SIGNAL( msgTagListChanged() ), w, SLOT( populateStatusFilterCombo() ) ); + connect( w, SIGNAL(statusMessage(QString)), + KPIM::BroadcastStatus::instance(), SLOT(setStatusMsg(QString)) ); + + updateTabControls(); return w; } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/messagelistview/storagemodel.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/messagelistview/storagemodel.cpp --- kde-nightly-kdepim-20091006+svn1032120/kmail/messagelistview/storagemodel.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/messagelistview/storagemodel.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -24,7 +24,7 @@ #include -#include +#include #include #include diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/objecttreeparser.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/objecttreeparser.cpp --- kde-nightly-kdepim-20091006+svn1032120/kmail/objecttreeparser.cpp 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/objecttreeparser.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -213,6 +213,11 @@ partNode* parentNode = &startNode; partNode* newNode = new partNode(false, myBody); + + // Build the object tree of the new node before setting the parent, as otherwise + // buildObjectTree() would erronously modify the parents as well + newNode->buildObjectTree( false ); + if ( append && parentNode->firstChild() ) { parentNode = parentNode->firstChild(); while( parentNode->nextSibling() ) @@ -221,8 +226,6 @@ } else parentNode->setFirstChild( newNode ); - newNode->buildObjectTree( false ); - if ( startNode.mimePartTreeItem() ) { newNode->fillMimePartTree( startNode.mimePartTreeItem(), 0, QString(), QString(), QString(), 0, diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/objecttreeparser.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/objecttreeparser.h --- kde-nightly-kdepim-20091006+svn1032120/kmail/objecttreeparser.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/objecttreeparser.h 2009-10-09 23:30:58.000000000 +0100 @@ -114,7 +114,9 @@ virtual ~ObjectTreeParser(); void setAllowAsync( bool allow ) { assert( !mHasPendingAsyncJobs ); mAllowAsync = allow; } - bool allowAsync() const { return mAllowAsync; } + + // ### disabled async mode because of crashes, see bug 208353 + bool allowAsync() const { return /*mAllowAsync*/false; } bool hasPendingAsyncJobs() const { return mHasPendingAsyncJobs; } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/objecttreeparser_p.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/objecttreeparser_p.cpp --- kde-nightly-kdepim-20091006+svn1032120/kmail/objecttreeparser_p.cpp 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/objecttreeparser_p.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -48,14 +48,31 @@ using namespace Kleo; using namespace GpgME; -DecryptVerifyBodyPartMemento::DecryptVerifyBodyPartMemento( DecryptVerifyJob * job, const QByteArray & cipherText ) +CryptoBodyPartMemento::CryptoBodyPartMemento() : QObject( 0 ), Interface::BodyPartMemento(), ISubject(), - m_cipherText( cipherText ), - m_job( job ), m_running( false ) { + +} + +CryptoBodyPartMemento::~CryptoBodyPartMemento() {} + +void CryptoBodyPartMemento::setAuditLog( const Error & err, const QString & log ) { + m_auditLogError = err; + m_auditLog = log; +} + +void CryptoBodyPartMemento::setRunning( bool running ) { + m_running = running; +} + +DecryptVerifyBodyPartMemento::DecryptVerifyBodyPartMemento( DecryptVerifyJob * job, const QByteArray & cipherText ) + : CryptoBodyPartMemento(), + m_cipherText( cipherText ), + m_job( job ) +{ assert( m_job ); } @@ -72,14 +89,14 @@ } connect( m_job, SIGNAL(result(const GpgME::DecryptionResult&,const GpgME::VerificationResult&,const QByteArray&)), this, SLOT(slotResult(const GpgME::DecryptionResult&,const GpgME::VerificationResult&,const QByteArray&)) ); - m_running = true; + setRunning( true ); return true; } void DecryptVerifyBodyPartMemento::exec() { assert( m_job ); QByteArray plainText; - m_running = true; + setRunning( true ); const std::pair p = m_job->exec( m_cipherText, plainText ); saveResult( p.first, p.second, plainText ); m_job->deleteLater(); // exec'ed jobs don't delete themselves @@ -91,12 +108,11 @@ const QByteArray & plainText ) { assert( m_job ); - m_running = false; + setRunning( false ); m_dr = dr; m_vr = vr; m_plainText = plainText; - m_auditLog = m_job->auditLogAsHtml(); - m_auditLogError = m_job->auditLogError(); + setAuditLog( m_job->auditLogError(), m_job->auditLogAsHtml() ); } void DecryptVerifyBodyPartMemento::slotResult( const DecryptionResult & dr, @@ -105,7 +121,7 @@ { saveResult( dr, vr, plainText ); m_job = 0; - QTimer::singleShot( 100, this, SLOT(notify()) ); + notify(); } @@ -115,14 +131,11 @@ KeyListJob * klj, const QByteArray & signature, const QByteArray & plainText ) - : QObject( 0 ), - Interface::BodyPartMemento(), - ISubject(), + : CryptoBodyPartMemento(), m_signature( signature ), m_plainText( plainText ), m_job( job ), - m_keylistjob( klj ), - m_running( false ) + m_keylistjob( klj ) { assert( m_job ); } @@ -142,13 +155,13 @@ } connect( m_job, SIGNAL(result(const GpgME::VerificationResult&)), this, SLOT(slotResult(const GpgME::VerificationResult&)) ); - m_running = true; + setRunning( true ); return true; } void VerifyDetachedBodyPartMemento::exec() { assert( m_job ); - m_running = true; + setRunning( true ); saveResult( m_job->exec( m_signature, m_plainText ) ); m_job->deleteLater(); // exec'ed jobs don't delete themselves m_job = 0; @@ -161,7 +174,7 @@ if ( m_keylistjob ) m_keylistjob->deleteLater(); // exec'ed jobs don't delete themselves m_keylistjob = 0; - m_running = false; + setRunning( false ); } bool VerifyDetachedBodyPartMemento::canStartKeyListJob() const @@ -182,8 +195,7 @@ { assert( m_job ); m_vr = vr; - m_auditLog = m_job->auditLogAsHtml(); - m_auditLogError = m_job->auditLogError(); + setAuditLog( m_job->auditLogError(), m_job->auditLogAsHtml() ); } void VerifyDetachedBodyPartMemento::slotResult( const VerificationResult & vr ) @@ -195,8 +207,8 @@ if ( m_keylistjob ) m_keylistjob->deleteLater(); m_keylistjob = 0; - m_running = false; - QTimer::singleShot( 100, this, SLOT(notify()) ); + setRunning( false ); + notify(); } bool VerifyDetachedBodyPartMemento::startKeyListJob() @@ -218,21 +230,18 @@ void VerifyDetachedBodyPartMemento::slotKeyListJobDone() { m_keylistjob = 0; - m_running = false; - QTimer::singleShot( 100, this, SLOT(notify()) ); + setRunning( false ); + notify(); } VerifyOpaqueBodyPartMemento::VerifyOpaqueBodyPartMemento( VerifyOpaqueJob * job, KeyListJob * klj, const QByteArray & signature ) - : QObject( 0 ), - Interface::BodyPartMemento(), - ISubject(), + : CryptoBodyPartMemento(), m_signature( signature ), m_job( job ), - m_keylistjob( klj ), - m_running( false ) + m_keylistjob( klj ) { assert( m_job ); } @@ -252,13 +261,13 @@ } connect( m_job, SIGNAL(result(const GpgME::VerificationResult&,const QByteArray&)), this, SLOT(slotResult(const GpgME::VerificationResult&,const QByteArray&)) ); - m_running = true; + setRunning( true ); return true; } void VerifyOpaqueBodyPartMemento::exec() { assert( m_job ); - m_running = true; + setRunning( true ); QByteArray plainText; saveResult( m_job->exec( m_signature, plainText ), plainText ); m_job->deleteLater(); // exec'ed jobs don't delete themselves @@ -272,7 +281,7 @@ if ( m_keylistjob ) m_keylistjob->deleteLater(); // exec'ed jobs don't delete themselves m_keylistjob = 0; - m_running = false; + setRunning( false ); } bool VerifyOpaqueBodyPartMemento::canStartKeyListJob() const @@ -295,8 +304,7 @@ assert( m_job ); m_vr = vr; m_plainText = plainText; - m_auditLog = m_job->auditLogAsHtml(); - m_auditLogError = m_job->auditLogError(); + setAuditLog( m_job->auditLogError(), m_job->auditLogAsHtml() ); } void VerifyOpaqueBodyPartMemento::slotResult( const VerificationResult & vr, @@ -309,8 +317,8 @@ if ( m_keylistjob ) m_keylistjob->deleteLater(); m_keylistjob = 0; - m_running = false; - QTimer::singleShot( 100, this, SLOT(notify()) ); + setRunning( false ); + notify(); } bool VerifyOpaqueBodyPartMemento::startKeyListJob() @@ -332,8 +340,8 @@ void VerifyOpaqueBodyPartMemento::slotKeyListJobDone() { m_keylistjob = 0; - m_running = false; - QTimer::singleShot( 100, this, SLOT(notify()) ); + setRunning( false ); + notify(); } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/objecttreeparser_p.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/objecttreeparser_p.h --- kde-nightly-kdepim-20091006+svn1032120/kmail/objecttreeparser_p.h 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/objecttreeparser_p.h 2009-10-09 23:30:58.000000000 +0100 @@ -54,37 +54,53 @@ namespace KMail { - class DecryptVerifyBodyPartMemento + class CryptoBodyPartMemento : public QObject, public KMail::Interface::BodyPartMemento, public KMail::ISubject { Q_OBJECT public: - DecryptVerifyBodyPartMemento( Kleo::DecryptVerifyJob * job, const QByteArray & cipherText ); - ~DecryptVerifyBodyPartMemento(); + CryptoBodyPartMemento(); + ~CryptoBodyPartMemento(); /* reimp */ Interface::Observer * asObserver() { return 0; } /* reimp */ Interface::Observable * asObservable() { return this; } + bool isRunning() const { return m_running; } + + const QString & auditLogAsHtml() const { return m_auditLog; } + GpgME::Error auditLogError() const { return m_auditLogError; } + + protected: + void setAuditLog( const GpgME::Error & err, const QString & log ); + void setRunning( bool running ); + + private: + bool m_running; + QString m_auditLog; + GpgME::Error m_auditLogError; + }; + + class DecryptVerifyBodyPartMemento + : public CryptoBodyPartMemento + { + Q_OBJECT + public: + DecryptVerifyBodyPartMemento( Kleo::DecryptVerifyJob * job, const QByteArray & cipherText ); + ~DecryptVerifyBodyPartMemento(); + bool start(); void exec(); - bool isRunning() const { return m_running; } - const QByteArray & plainText() const { return m_plainText; } const GpgME::DecryptionResult & decryptResult() const { return m_dr; } const GpgME::VerificationResult & verifyResult() const { return m_vr; } - const QString & auditLogAsHtml() const { return m_auditLog; } - GpgME::Error auditLogError() const { return m_auditLogError; } private slots: void slotResult( const GpgME::DecryptionResult & dr, const GpgME::VerificationResult & vr, const QByteArray & plainText ); - void notify() { - ISubject::notify(); - } private: void saveResult( const GpgME::DecryptionResult &, @@ -94,20 +110,15 @@ // input: const QByteArray m_cipherText; QPointer m_job; - bool m_running; // output: GpgME::DecryptionResult m_dr; GpgME::VerificationResult m_vr; QByteArray m_plainText; - QString m_auditLog; - GpgME::Error m_auditLogError; }; class VerifyDetachedBodyPartMemento - : public QObject, - public KMail::Interface::BodyPartMemento, - public KMail::ISubject + : public CryptoBodyPartMemento { Q_OBJECT public: @@ -117,26 +128,16 @@ const QByteArray & plainText ); ~VerifyDetachedBodyPartMemento(); - /* reimp */ Interface::Observer * asObserver() { return 0; } - /* reimp */ Interface::Observable * asObservable() { return this; } - bool start(); void exec(); - bool isRunning() const { return m_running; } - const GpgME::VerificationResult & verifyResult() const { return m_vr; } - const QString & auditLogAsHtml() const { return m_auditLog; } - GpgME::Error auditLogError() const { return m_auditLogError; } const GpgME::Key & signingKey() const { return m_key; } private slots: void slotResult( const GpgME::VerificationResult & vr ); void slotKeyListJobDone(); void slotNextKey( const GpgME::Key & ); - void notify() { - ISubject::notify(); - } private: void saveResult( const GpgME::VerificationResult & ); @@ -149,19 +150,14 @@ const QByteArray m_plainText; QPointer m_job; QPointer m_keylistjob; - bool m_running; // output: GpgME::VerificationResult m_vr; - QString m_auditLog; - GpgME::Error m_auditLogError; GpgME::Key m_key; }; class VerifyOpaqueBodyPartMemento - : public QObject, - public KMail::Interface::BodyPartMemento, - public KMail::ISubject + : public CryptoBodyPartMemento { Q_OBJECT public: @@ -170,18 +166,11 @@ const QByteArray & signature ); ~VerifyOpaqueBodyPartMemento(); - /* reimp */ Interface::Observer * asObserver() { return 0; } - /* reimp */ Interface::Observable * asObservable() { return this; } - bool start(); void exec(); - bool isRunning() const { return m_running; } - const QByteArray & plainText() const { return m_plainText; } const GpgME::VerificationResult & verifyResult() const { return m_vr; } - const QString & auditLogAsHtml() const { return m_auditLog; } - GpgME::Error auditLogError() const { return m_auditLogError; } const GpgME::Key & signingKey() const { return m_key; } private slots: @@ -189,9 +178,6 @@ const QByteArray & plainText ); void slotKeyListJobDone(); void slotNextKey( const GpgME::Key & ); - void notify() { - ISubject::notify(); - } private: void saveResult( const GpgME::VerificationResult &, @@ -204,12 +190,9 @@ const QByteArray m_signature; QPointer m_job; QPointer m_keylistjob; - bool m_running; // output: GpgME::VerificationResult m_vr; QByteArray m_plainText; - QString m_auditLog; - GpgME::Error m_auditLogError; GpgME::Key m_key; }; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/partNode.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/partNode.cpp --- kde-nightly-kdepim-20091006+svn1032120/kmail/partNode.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/partNode.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -181,7 +181,8 @@ #ifndef NDEBUG void partNode::dump( int chars ) const { kDebug() << QString().fill( ' ', chars ) <<"+" - << typeString() << '/' << subTypeString() << " embedded:" << mDisplayedEmbedded; + << typeString() << '/' << subTypeString() << " embedded:" << mDisplayedEmbedded + << " address:" << this; if ( mChild ) mChild->dump( chars + 1 ); if ( mNext ) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kmail/partNode.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kmail/partNode.h --- kde-nightly-kdepim-20091006+svn1032120/kmail/partNode.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kmail/partNode.h 2009-10-09 23:30:58.000000000 +0100 @@ -212,7 +212,7 @@ mMimePartTreeItem = item; } - KMMimePartTreeItem* mimePartTreeItem() { + KMMimePartTreeItem* mimePartTreeItem() const { return mMimePartTreeItem; } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kontact/plugins/summary/summaryview_part.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kontact/plugins/summary/summaryview_part.cpp --- kde-nightly-kdepim-20091006+svn1032120/kontact/plugins/summary/summaryview_part.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kontact/plugins/summary/summaryview_part.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -19,8 +19,9 @@ You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. + Boston, MA 02110-1301, USA. */ + #include "summaryview_part.h" #include @@ -156,27 +157,28 @@ QList::ConstIterator it = plugins.constBegin(); for ( ; it != end; ++it ) { KontactInterface::Plugin *plugin = *it; - if ( activeSummaries.contains( plugin->identifier() ) ) { - KontactInterface::Summary *summary = plugin->createSummaryWidget( mFrame ); + if ( !activeSummaries.contains( plugin->identifier() ) ) { + continue; + } - if ( summary ) { - if ( summary->summaryHeight() > 0 ) { - mSummaries.insert( plugin->identifier(), summary ); - - connect( summary, SIGNAL(message(const QString&)), - BroadcastStatus::instance(), SLOT(setStatusMsg(const QString&)) ); - connect( summary, SIGNAL(summaryWidgetDropped(QWidget*,QWidget*,int)), - this, SLOT(summaryWidgetMoved(QWidget*,QWidget*,int)) ); - - if ( !mLeftColumnSummaries.contains( plugin->identifier() ) && - !mRightColumnSummaries.contains( plugin->identifier() ) ) { - mLeftColumnSummaries.append( plugin->identifier() ); - } - - loadedSummaries.append( plugin->identifier() ); - } else { - summary->hide(); + KontactInterface::Summary *summary = plugin->createSummaryWidget( mFrame ); + if ( summary ) { + if ( summary->summaryHeight() > 0 ) { + mSummaries.insert( plugin->identifier(), summary ); + + connect( summary, SIGNAL(message(const QString&)), + BroadcastStatus::instance(), SLOT(setStatusMsg(const QString&)) ); + connect( summary, SIGNAL(summaryWidgetDropped(QWidget*,QWidget*,int)), + this, SLOT(summaryWidgetMoved(QWidget*,QWidget*,int)) ); + + if ( !mLeftColumnSummaries.contains( plugin->identifier() ) && + !mRightColumnSummaries.contains( plugin->identifier() ) ) { + mLeftColumnSummaries.append( plugin->identifier() ); } + + loadedSummaries.append( plugin->identifier() ); + } else { + summary->hide(); } } } @@ -229,8 +231,13 @@ mRightColumn->addWidget( mSummaries[ *strIt ] ); } } - QSpacerItem *lspacer = new QSpacerItem( 1, 1000 ); - QSpacerItem *rspacer = new QSpacerItem( 1, 1000 ); + + QSpacerItem *lspacer = new QSpacerItem( 1, 10, + QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding ); + QSpacerItem *rspacer = new QSpacerItem( 1, 10, + QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding ); mLeftColumn->addSpacerItem( lspacer ); mRightColumn->addSpacerItem( rspacer ); diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/kontact/src/Kontact.desktop /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/kontact/src/Kontact.desktop --- kde-nightly-kdepim-20091006+svn1032120/kontact/src/Kontact.desktop 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/kontact/src/Kontact.desktop 2009-10-09 23:30:58.000000000 +0100 @@ -122,5 +122,6 @@ X-KDE-StartupNotify=true X-DBUS-StartupType=Unique X-DBUS-ServiceName=org.kde.kontact +X-KDE-ServiceTypes=DBUS/ResourceBackend/IMAP Categories=Qt;KDE;Office;ProjectManagement; X-DocPath=kontact/index.html diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/korganizer/interfaces/calendar/calendardecoration.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/korganizer/interfaces/calendar/calendardecoration.h --- kde-nightly-kdepim-20091006+svn1032120/korganizer/interfaces/calendar/calendardecoration.h 2009-10-06 23:28:12.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/korganizer/interfaces/calendar/calendardecoration.h 2009-10-09 23:31:07.000000000 +0100 @@ -98,11 +98,11 @@ virtual KUrl url(); Q_SIGNALS: - virtual void gotNewPixmap( const QPixmap & ) const; - virtual void gotNewShortText( const QString & ) const; - virtual void gotNewLongText( const QString & ) const; - virtual void gotNewExtensiveText( const QString & ) const; - virtual void gotNewUrl( const KUrl & ) const; + void gotNewPixmap( const QPixmap & ) const; + void gotNewShortText( const QString & ) const; + void gotNewLongText( const QString & ) const; + void gotNewExtensiveText( const QString & ) const; + void gotNewUrl( const KUrl & ) const; protected: QString mId; diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/korganizer/kcmconfigs/korganizer_configfreebusy.desktop /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/korganizer/kcmconfigs/korganizer_configfreebusy.desktop --- kde-nightly-kdepim-20091006+svn1032120/korganizer/kcmconfigs/korganizer_configfreebusy.desktop 2009-10-06 23:28:12.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/korganizer/kcmconfigs/korganizer_configfreebusy.desktop 2009-10-09 23:31:08.000000000 +0100 @@ -18,7 +18,7 @@ Name[ca]=Lliure/ocupat Name[cs]=Aktivita Name[cy]=Rhydd/Prysur -Name[da]=Fri/Optaget +Name[da]=Ledig/optaget Name[de]=Frei/Belegt Name[el]=Free/Busy Name[en_GB]=Free/Busy @@ -75,7 +75,7 @@ Comment[ca]=Configuració de Lliure/ocupat per a KOrganizer Comment[cs]=Nastavení aktivity pro KOrganizer Comment[cy]=Ffurfweddiad Rhydd/Prysur KTrefnydd -Comment[da]=KOrganizer Fri/Optaget-indstilling +Comment[da]=KOrganizer indstilling af ledig/optaget Comment[de]=Frei/Belegt-Festlegung für KOrganizer Comment[el]=Ρυθμίσεις KOrganizer Free/Busy Comment[en_GB]=KOrganizer Free/Busy Configuration diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/korganizer/views/agendaview/koagendaview.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/korganizer/views/agendaview/koagendaview.cpp --- kde-nightly-kdepim-20091006+svn1032120/korganizer/views/agendaview/koagendaview.cpp 2009-10-06 23:28:12.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/korganizer/views/agendaview/koagendaview.cpp 2009-10-09 23:31:08.000000000 +0100 @@ -1525,7 +1525,7 @@ void KOAgendaView::setHolidayMasks() { - if ( mSelectedDates.isEmpty() ) { + if ( mSelectedDates.isEmpty() || !mSelectedDates[0].isValid() ) { return; } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/ktimetracker/csvexportdialog_base.ui /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/ktimetracker/csvexportdialog_base.ui --- kde-nightly-kdepim-20091006+svn1032120/ktimetracker/csvexportdialog_base.ui 2009-10-06 23:28:12.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/ktimetracker/csvexportdialog_base.ui 2009-10-09 23:31:09.000000000 +0100 @@ -43,7 +43,7 @@ - The file where Karm will write the data. + The file where KTimeTracker will write the data. diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/libkdepim/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/libkdepim/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/libkdepim/CMakeLists.txt 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/libkdepim/CMakeLists.txt 2009-10-09 23:30:57.000000000 +0100 @@ -1,3 +1,4 @@ +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) @@ -69,7 +70,6 @@ distributionlist.cpp sendsmsdialog.cpp categoryhierarchyreader.cpp - messagestatus.cpp kmailcompletion.cpp kmeditor.cpp autochecktreewidget.cpp @@ -81,7 +81,11 @@ QT4_ADD_DBUS_INTERFACE(kdepim_LIB_SRCS ${CMAKE_SOURCE_DIR}/korganizer/korgac/org.kde.korganizer.KOrgac.xml korganizer_korgac_interface ) -kde4_add_ui_files(kdepim_LIB_SRCS categoryselectdialog_base.ui categoryeditdialog_base.ui addresspicker.ui) +kde4_add_ui_files(kdepim_LIB_SRCS + categoryselectdialog_base.ui + categoryeditdialog_base.ui + addresspicker.ui +) kde4_add_library(kdepim SHARED ${kdepim_LIB_SRCS}) @@ -100,6 +104,7 @@ ${KDEPIMLIBS_KPIMTEXTEDIT_LIBS} ${KDEPIMLIBS_AKONADI_LIBS} ${KDEPIMLIBS_AKONADI_CONTACT_LIBS} + ${KDEPIMLIBS_KMIME_LIBS} ) target_link_libraries(kdepim LINK_INTERFACE_LIBRARIES diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/libkdepim/ldapclient.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/libkdepim/ldapclient.cpp --- kde-nightly-kdepim-20091006+svn1032120/libkdepim/ldapclient.cpp 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/libkdepim/ldapclient.cpp 2009-10-09 23:30:57.000000000 +0100 @@ -62,6 +62,7 @@ void LdapClient::setAttrs( const QStringList& attrs ) { mAttrs = attrs; + mAttrs << "objectClass"; // via objectClass we detect distribution lists } void LdapClient::startQuery( const QString& filter ) @@ -368,8 +369,7 @@ readWeighForClient( ldapClient, config, j ); QStringList attrs; - // note: we need "objectClass" to detect distribution lists - attrs << "cn" << "mail" << "givenname" << "sn" << "objectClass"; + attrs << "cn" << "mail" << "givenname" << "sn"; ldapClient->setAttrs( attrs ); connect( ldapClient, SIGNAL( result( const KPIM::LdapClient&, const KLDAP::LdapObject& ) ), diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/libkdepim/ldapsearchdialog.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/libkdepim/ldapsearchdialog.cpp --- kde-nightly-kdepim-20091006+svn1032120/libkdepim/ldapsearchdialog.cpp 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/libkdepim/ldapsearchdialog.cpp 2009-10-09 23:30:57.000000000 +0100 @@ -462,13 +462,19 @@ for ( int i = 0; i < mResultListView->topLevelItemCount(); i++ ) { ContactListItem *cli = static_cast( mResultListView->topLevelItem( i ) ); if ( cli->isSelected() ) { - QString email = asUtf8( cli->mAttrs[ "mail" ].first() ).trimmed(); - if ( !email.isEmpty() ) { - QString name = asUtf8( cli->mAttrs[ "cn" ].first() ).trimmed(); - if ( name.isEmpty() ) { - result << email; - } else { - result << name + " <" + email + '>'; + const KLDAP::LdapAttrValue &mailAttrs = cli->mAttrs[ "mail" ]; + if ( mailAttrs.size() >= 1 ) { + QString email = asUtf8( mailAttrs.first() ).trimmed(); + if ( !email.isEmpty() ) { + const KLDAP::LdapAttrValue &nameAttrs = cli->mAttrs[ "cn" ]; + if ( nameAttrs.size() > 1 ) { + QString name = asUtf8( nameAttrs.first() ).trimmed(); + if ( name.isEmpty() ) { + result << email; + } else { + result << name + " <" + email + '>'; + } + } } } } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/libkdepim/messagestatus.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/libkdepim/messagestatus.cpp --- kde-nightly-kdepim-20091006+svn1032120/libkdepim/messagestatus.cpp 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/libkdepim/messagestatus.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,799 +0,0 @@ -/* - This file is part of KDEPIM. - Copyright (c) 2003 Andreas Gungl - - KMail is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - KMail 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 - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include "messagestatus.h" - -#include -#include - -using namespace KPIM; - -/** The message status format. These can be or'd together. - Note, that the KMMsgStatusIgnored implies the - status to be Read even if the flags are set - to Unread or New. This is done in isRead() - and related getters. So we can preserve the state - when switching a thread to Ignored and back. */ -enum MsgStatus { - KMMsgStatusUnknown = 0x00000000, - KMMsgStatusNew = 0x00000001, - KMMsgStatusUnread = 0x00000002, - KMMsgStatusRead = 0x00000004, - KMMsgStatusOld = 0x00000008, - KMMsgStatusDeleted = 0x00000010, - KMMsgStatusReplied = 0x00000020, - KMMsgStatusForwarded = 0x00000040, - KMMsgStatusQueued = 0x00000080, - KMMsgStatusSent = 0x00000100, - KMMsgStatusFlag = 0x00000200, // flag means important - KMMsgStatusWatched = 0x00000400, - KMMsgStatusIgnored = 0x00000800, // forces isRead() - KMMsgStatusToAct = 0x00001000, - KMMsgStatusSpam = 0x00002000, - KMMsgStatusHam = 0x00004000, - KMMsgStatusHasAttach = 0x00008000 -}; - -MessageStatus::MessageStatus() -{ - mStatus = KMMsgStatusUnknown; -} - -MessageStatus &MessageStatus::operator = ( const MessageStatus &other ) -{ - mStatus = other.mStatus; - return *this; -} - -bool MessageStatus::operator == ( const MessageStatus &other ) const -{ - return ( mStatus == other.mStatus ); -} - -bool MessageStatus::operator != ( const MessageStatus &other ) const -{ - return ( mStatus != other.mStatus ); -} - -bool MessageStatus::operator & ( const MessageStatus &other ) const -{ - return ( mStatus & other.mStatus ); -} - -void MessageStatus::clear() -{ - mStatus = KMMsgStatusUnknown; -} - -void MessageStatus::set( const MessageStatus &other ) -{ - // Those stati are exclusive, but we have to lock at the - // internal representation because Ignored can manipulate - // the result of the getter methods. - if ( other.mStatus & KMMsgStatusNew ) { - setNew(); - } - if ( other.mStatus & KMMsgStatusUnread ) { - setUnread(); - } - if ( other.mStatus & KMMsgStatusRead ) { - setRead(); - } - if ( other.mStatus & KMMsgStatusOld ) { - setOld(); - } - - if ( other.isDeleted() ) { - setDeleted(); - } - if ( other.isReplied() ) { - setReplied(); - } - if ( other.isForwarded() ) { - setForwarded(); - } - if ( other.isQueued() ) { - setQueued(); - } - if ( other.isSent() ) { - setSent(); - } - if ( other.isImportant() ) { - setImportant(); - } - - if ( other.isWatched() ) { - setWatched(); - } - if ( other.isIgnored() ) { - setIgnored(); - } - if ( other.isToAct() ) { - setToAct(); - } - if ( other.isSpam() ) { - setSpam(); - } - if ( other.isHam() ) { - setHam(); - } - if ( other.hasAttachment() ) { - setHasAttachment(); - } -} - -void MessageStatus::toggle( const MessageStatus &other ) -{ - if ( other.isDeleted() ) { - setDeleted( !( mStatus & KMMsgStatusDeleted ) ); - } - if ( other.isReplied() ) { - setReplied( !( mStatus & KMMsgStatusReplied ) ); - } - if ( other.isForwarded() ) { - setForwarded( !( mStatus & KMMsgStatusForwarded ) ); - } - if ( other.isQueued() ) { - setQueued( !( mStatus & KMMsgStatusQueued ) ); - } - if ( other.isSent() ) { - setSent( !( mStatus & KMMsgStatusSent ) ); - } - if ( other.isImportant() ) { - setImportant( !( mStatus & KMMsgStatusFlag ) ); - } - - if ( other.isWatched() ) { - setWatched( !( mStatus & KMMsgStatusWatched ) ); - } - if ( other.isIgnored() ) { - setIgnored( !( mStatus & KMMsgStatusIgnored ) ); - } - if ( other.isToAct() ) { - setToAct( !( mStatus & KMMsgStatusToAct ) ); - } - if ( other.isSpam() ) { - setSpam( !( mStatus & KMMsgStatusSpam ) ); - } - if ( other.isHam() ) { - setHam( !( mStatus & KMMsgStatusHam ) ); - } - if ( other.hasAttachment() ) { - setHasAttachment( !( mStatus & KMMsgStatusHasAttach ) ); - } -} - -bool MessageStatus::isOfUnknownStatus() const -{ - return ( mStatus == KMMsgStatusUnknown ); -} - -bool MessageStatus::isNew() const -{ - return ( mStatus & KMMsgStatusNew && !( mStatus & KMMsgStatusIgnored ) ); -} - -bool MessageStatus::isUnread() const -{ - return ( mStatus & KMMsgStatusUnread && !( mStatus & KMMsgStatusIgnored ) ); -} - -bool MessageStatus::isRead() const -{ - return ( mStatus & KMMsgStatusRead || mStatus & KMMsgStatusIgnored ); -} - -bool MessageStatus::isOld() const -{ - return ( mStatus & KMMsgStatusOld ); -} - -bool MessageStatus::isDeleted() const -{ - return ( mStatus & KMMsgStatusDeleted ); -} - -bool MessageStatus::isReplied() const -{ - return ( mStatus & KMMsgStatusReplied ); -} - -bool MessageStatus::isForwarded() const -{ - return ( mStatus & KMMsgStatusForwarded ); -} - -bool MessageStatus::isQueued() const -{ - return ( mStatus & KMMsgStatusQueued ); -} - -bool MessageStatus::isSent() const -{ - return ( mStatus & KMMsgStatusSent ); -} - -bool MessageStatus::isImportant() const -{ - return ( mStatus & KMMsgStatusFlag ); -} - -bool MessageStatus::isWatched() const -{ - return ( mStatus & KMMsgStatusWatched ); -} - -bool MessageStatus::isIgnored() const -{ - return ( mStatus & KMMsgStatusIgnored ); -} - -bool MessageStatus::isToAct() const -{ - return ( mStatus & KMMsgStatusToAct ); -} - -bool MessageStatus::isSpam() const -{ - return ( mStatus & KMMsgStatusSpam ); -} - -bool MessageStatus::isHam() const -{ - return ( mStatus & KMMsgStatusHam ); -} - -bool MessageStatus::hasAttachment() const -{ - return ( mStatus & KMMsgStatusHasAttach ); -} - -void MessageStatus::setNew() -{ - // new overrides old and read - mStatus &= ~KMMsgStatusOld; - mStatus &= ~KMMsgStatusRead; - mStatus &= ~KMMsgStatusUnread; - mStatus |= KMMsgStatusNew; -} - -void MessageStatus::setUnread() -{ - // unread overrides read - mStatus &= ~KMMsgStatusOld; - mStatus &= ~KMMsgStatusRead; - mStatus &= ~KMMsgStatusNew; - mStatus |= KMMsgStatusUnread; -} - -void MessageStatus::setRead() -{ - // Unset unread and new, set read - mStatus &= ~KMMsgStatusUnread; - mStatus &= ~KMMsgStatusNew; - mStatus |= KMMsgStatusRead; -} - -void MessageStatus::setOld() -{ - // old can't be new or unread - mStatus &= ~KMMsgStatusNew; - mStatus &= ~KMMsgStatusUnread; - mStatus |= KMMsgStatusOld; -} - -void MessageStatus::setDeleted( bool deleted ) -{ - if ( deleted ) { - mStatus |= KMMsgStatusDeleted; - } else { - mStatus &= ~KMMsgStatusDeleted; - } -} - -void MessageStatus::setReplied( bool replied ) -{ - if ( replied ) { - mStatus |= KMMsgStatusReplied; - } else { - mStatus &= ~KMMsgStatusReplied; - } -} - -void MessageStatus::setForwarded( bool forwarded ) -{ - if ( forwarded ) { - mStatus |= KMMsgStatusForwarded; - } else { - mStatus &= ~KMMsgStatusForwarded; - } -} - -void MessageStatus::setQueued( bool queued ) -{ - if ( queued ) { - mStatus |= KMMsgStatusQueued; - } else { - mStatus &= ~KMMsgStatusQueued; - } -} - -void MessageStatus::setSent( bool sent ) -{ - if ( sent ) { - mStatus &= ~KMMsgStatusQueued; - // FIXME to be discussed if sent messages are Read - mStatus &= ~KMMsgStatusUnread; - mStatus &= ~KMMsgStatusNew; - mStatus |= KMMsgStatusSent; - } else { - mStatus &= ~KMMsgStatusSent; - } -} - -void MessageStatus::setImportant( bool important ) -{ - if ( important ) { - mStatus |= KMMsgStatusFlag; - } else { - mStatus &= ~KMMsgStatusFlag; - } -} - -// Watched and ignored are mutually exclusive -void MessageStatus::setWatched( bool watched ) -{ - if ( watched ) { - mStatus &= ~KMMsgStatusIgnored; - mStatus |= KMMsgStatusWatched; - } else { - mStatus &= ~KMMsgStatusWatched; - } -} - -void MessageStatus::setIgnored( bool ignored ) -{ - if ( ignored ) { - mStatus &= ~KMMsgStatusWatched; - mStatus |= KMMsgStatusIgnored; - } else { - mStatus &= ~KMMsgStatusIgnored; - } -} - -void MessageStatus::setToAct( bool toAct ) -{ - if ( toAct ) { - mStatus |= KMMsgStatusToAct; - } else { - mStatus &= ~KMMsgStatusToAct; - } -} - -// Ham and Spam are mutually exclusive -void MessageStatus::setSpam( bool spam ) -{ - if ( spam ) { - mStatus &= ~KMMsgStatusHam; - mStatus |= KMMsgStatusSpam; - } else { - mStatus &= ~KMMsgStatusSpam; - } -} - -void MessageStatus::setHam( bool ham ) -{ - if ( ham ) { - mStatus &= ~KMMsgStatusSpam; - mStatus |= KMMsgStatusHam; - } else { - mStatus &= ~KMMsgStatusHam; - } -} - -void MessageStatus::setHasAttachment( bool withAttachment ) -{ - if ( withAttachment ) { - mStatus |= KMMsgStatusHasAttach; - } else { - mStatus &= ~KMMsgStatusHasAttach; - } -} - -qint32 MessageStatus::toQInt32() const -{ - return mStatus; -} - -void MessageStatus::fromQInt32( qint32 status ) -{ - mStatus = status; -} - -QString MessageStatus::getStatusStr() const -{ - QString sstr; - if ( mStatus & KMMsgStatusNew ) { - sstr += 'N'; - } - if ( mStatus & KMMsgStatusUnread ) { - sstr += 'U'; - } - if ( mStatus & KMMsgStatusOld ) { - sstr += 'O'; - } - if ( mStatus & KMMsgStatusRead ) { - sstr += 'R'; - } - if ( mStatus & KMMsgStatusDeleted ) { - sstr += 'D'; - } - if ( mStatus & KMMsgStatusReplied ) { - sstr += 'A'; - } - if ( mStatus & KMMsgStatusForwarded ) { - sstr += 'F'; - } - if ( mStatus & KMMsgStatusQueued ) { - sstr += 'Q'; - } - if ( mStatus & KMMsgStatusToAct ) { - sstr += 'K'; - } - if ( mStatus & KMMsgStatusSent ) { - sstr += 'S'; - } - if ( mStatus & KMMsgStatusFlag ) { - sstr += 'G'; - } - if ( mStatus & KMMsgStatusWatched ) { - sstr += 'W'; - } - if ( mStatus & KMMsgStatusIgnored ) { - sstr += 'I'; - } - if ( mStatus & KMMsgStatusSpam ) { - sstr += 'P'; - } - if ( mStatus & KMMsgStatusHam ) { - sstr += 'H'; - } - if ( mStatus & KMMsgStatusHasAttach ) { - sstr += 'T'; - } - - return sstr; -} - -void MessageStatus::setStatusFromStr( QString aStr ) -{ - mStatus = KMMsgStatusUnknown; - - if ( aStr.contains( 'N' ) ) { - setNew(); - } - if ( aStr.contains( 'U' ) ) { - setUnread(); - } - if ( aStr.contains( 'O' ) ) { - setOld(); - } - if ( aStr.contains( 'R' ) ) { - setRead(); - } - if ( aStr.contains( 'D' ) ) { - setDeleted(); - } - if ( aStr.contains( 'A' ) ) { - setReplied(); - } - if ( aStr.contains( 'F' ) ) { - setForwarded(); - } - if ( aStr.contains( 'Q' ) ) { - setQueued(); - } - if ( aStr.contains( 'K' ) ) { - setToAct(); - } - if ( aStr.contains( 'S' ) ) { - setSent(); - } - if ( aStr.contains( 'G' ) ) { - setImportant(); - } - if ( aStr.contains( 'W' ) ) { - setWatched(); - } - if ( aStr.contains( 'I' ) ) { - setIgnored(); - } - if ( aStr.contains( 'P' ) ) { - setSpam(); - } - if ( aStr.contains( 'H' ) ) { - setHam(); - } - if ( aStr.contains( 'T' ) ) { - setHasAttachment(); - } - if ( aStr.contains( 'C' ) ) { - setHasAttachment( false ); - } -} - -QString MessageStatus::getSortRank() const -{ - QString sstr = "bcbbbbbbbb"; - - // put watched ones first, then normal ones, ignored ones last - if ( mStatus & KMMsgStatusWatched ) { - sstr[0] = 'a'; - } - if ( mStatus & KMMsgStatusIgnored ) { - sstr[0] = 'c'; - } - - // Second level. One of new, old, read, unread - if ( mStatus & KMMsgStatusNew ) { - sstr[1] = 'a'; - } - if ( mStatus & KMMsgStatusUnread ) { - sstr[1] = 'b'; - } - //if ( mStatus & KMMsgStatusOld ) { - // sstr[1] = 'c'; - //} - //if ( mStatus & KMMsgStatusRead ) { - // sstr[1] = 'c'; - //} - - // Third level. In somewhat arbitrary order. - if ( mStatus & KMMsgStatusDeleted ) { - sstr[2] = 'a'; - } - if ( mStatus & KMMsgStatusFlag ) { - sstr[3] = 'a'; - } - if ( mStatus & KMMsgStatusReplied ) { - sstr[4] = 'a'; - } - if ( mStatus & KMMsgStatusForwarded ) { - sstr[5] = 'a'; - } - if ( mStatus & KMMsgStatusQueued ) { - sstr[6] = 'a'; - } - if ( mStatus & KMMsgStatusSent ) { - sstr[7] = 'a'; - } - if ( mStatus & KMMsgStatusHam ) { - sstr[8] = 'a'; - } - if ( mStatus & KMMsgStatusSpam ) { - sstr[8] = 'c'; - } - if ( mStatus & KMMsgStatusToAct ) { - sstr[9] = 'a'; - } - - return sstr; -} - -QSet MessageStatus::getStatusFlags() const -{ - QSet flags; - - // Non handled status: - // * KMMsgStatusQueued - // * KMMsgStatusSent - // * KMMsgStatusSpam - // * KMMsgStatusHam - // * KMMsgStatusHasAttach - - if ( mStatus & KMMsgStatusDeleted ) { - flags+= "\\DELETED"; - } else { - if ( mStatus & ( KMMsgStatusOld | KMMsgStatusRead ) ) - flags+= "\\SEEN "; - if ( mStatus & KMMsgStatusReplied ) - flags+= "\\ANSWERED "; - if ( mStatus & KMMsgStatusFlag ) - flags+= "\\FLAGGED "; - // non standard flags - if ( mStatus & KMMsgStatusForwarded ) - flags+= "$FORWARDED "; - if ( mStatus & KMMsgStatusToAct ) - flags+= "$TODO "; - if ( mStatus & KMMsgStatusWatched ) - flags+= "$WATCHED "; - if ( mStatus & KMMsgStatusIgnored ) - flags+= "$IGNORED "; - } - - return flags; -} - -void MessageStatus::setStatusFromFlags( const QSet &flags ) -{ - mStatus = KMMsgStatusUnknown; - setNew(); - - // Non handled status: - // * KMMsgStatusQueued - // * KMMsgStatusSent - // * KMMsgStatusSpam - // * KMMsgStatusHam - // * KMMsgStatusHasAttach - - foreach ( const QByteArray &flag, flags ) { - if ( flag.toUpper() == QByteArray( "\\DELETED" ) ) { - setDeleted(); - } else if ( flag.toUpper() == QByteArray( "\\SEEN" ) ) { - setRead(); - } else if ( flag.toUpper() == QByteArray( "\\ANSWERED" ) ) { - setReplied(); - } else if ( flag.toUpper() == QByteArray( "\\FLAGGED" ) ) { - setImportant(); - - // non standard flags - } else if ( flag.toUpper() == QByteArray( "$FORWARDED" ) ) { - setForwarded(); - } else if ( flag.toUpper() == QByteArray( "$TODO" ) ) { - setToAct(); - } else if ( flag.toUpper() == QByteArray( "$WATCHED" ) ) { - setWatched(); - } else if ( flag.toUpper() == QByteArray( "$IGNORED" ) ) { - setIgnored(); - } else { - kWarning() << "Unknown flag:" << flag; - } - } -} - -MessageStatus MessageStatus::statusNew() -{ - MessageStatus st; - st.setNew(); - return st; -} - -MessageStatus MessageStatus::statusRead() -{ - MessageStatus st; - st.setRead(); - return st; -} - -MessageStatus MessageStatus::statusUnread() -{ - MessageStatus st; - st.setUnread(); - return st; -} - -MessageStatus MessageStatus::statusNewAndUnread() -{ - MessageStatus st; - // set the "new and unread" pseudo status; we have to set the internal - // representation directly because new and unread are mutually exclusive - st.fromQInt32( statusNew().toQInt32() | statusUnread().toQInt32() ); - return st; -} - -MessageStatus MessageStatus::statusOld() -{ - MessageStatus st; - st.setOld(); - return st; -} - -MessageStatus MessageStatus::statusDeleted() -{ - MessageStatus st; - st.setDeleted(); - return st; -} - -MessageStatus MessageStatus::statusReplied() -{ - MessageStatus st; - st.setReplied(); - return st; -} - -MessageStatus MessageStatus::statusForwarded() -{ - MessageStatus st; - st.setForwarded(); - return st; -} - -MessageStatus MessageStatus::statusQueued() -{ - MessageStatus st; - st.setQueued(); - return st; -} - -MessageStatus MessageStatus::statusSent() -{ - MessageStatus st; - st.setSent(); - return st; -} - -MessageStatus MessageStatus::statusImportant() -{ - MessageStatus st; - st.setImportant(); - return st; -} - -MessageStatus MessageStatus::statusWatched() -{ - MessageStatus st; - st.setWatched(); - return st; -} - -MessageStatus MessageStatus::statusIgnored() -{ - MessageStatus st; - st.setIgnored(); - return st; -} - -MessageStatus MessageStatus::statusToAct() -{ - MessageStatus st; - st.setToAct(); - return st; -} - -MessageStatus MessageStatus::statusSpam() -{ - MessageStatus st; - st.setSpam(); - return st; -} - -MessageStatus MessageStatus::statusHam() -{ - MessageStatus st; - st.setHam(); - return st; -} - -MessageStatus MessageStatus::statusHasAttachment() -{ - MessageStatus st; - st.setHasAttachment(); - return st; -} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/libkdepim/messagestatus.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/libkdepim/messagestatus.h --- kde-nightly-kdepim-20091006+svn1032120/libkdepim/messagestatus.h 2009-10-06 23:28:04.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/libkdepim/messagestatus.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,419 +0,0 @@ -/* -*- mode: C++ -*- - This file is part of KDEPIM. - Copyright (c) 2005 Andreas Gungl - - KMail is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - KMail 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 - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ -#ifndef KDEPIM_MESSAGESTATUS_H -#define KDEPIM_MESSAGESTATUS_H - -#include - -#include "kdepim_export.h" - -class QString; - -namespace KPIM { - -//--------------------------------------------------------------------------- -/** - @short KDEPIM Message Status. - @author Andreas Gungl - - The class encapsulates the handling of the different flags - which describe the status of a message. - The flags itself are not intended to be used outside this class. - - In the status pairs Watched/Ignored and Spam/Ham, there both - values can't be set at the same time, however they can - be unset at the same time. - - The stati New/Unread/Read/Old are mutually exclusive. -*/ -class KDEPIM_EXPORT MessageStatus -{ - public: - /** Constructor - sets status initially to unknown. */ - MessageStatus(); - - /** Assign the status from another instance. The internal - representation is identical afterwards, i.e. a comparison - by operator == will return true. - */ - MessageStatus &operator = ( const MessageStatus &other ); - - /** Compare the status with that from another instance. - @return true if the stati are equal, false if different. - */ - bool operator == ( const MessageStatus &other ) const; - - /** Compare the status with that from another instance. - @return true if the stati are equal, false if different. - */ - bool operator != ( const MessageStatus &other ) const; - - /** Check, if some of the flags in the status match - with those flags from another instance. - @return true if at least one flag is set in both stati. - */ - bool operator & ( const MessageStatus &other ) const; - - /** Clear all status flags, this resets to unknown. */ - void clear(); - - /** Set / add stati described by another MessageStatus object. - This can be used to merge in multiple stati at once without - using the single setter methods. - However, internally the setters are used anyway to ensure the - integrity of the resulting status. - */ - void set( const MessageStatus &other ); - - /** Toggle one or more stati described by another MessageStatus object. - Internally the setters are used to ensure the integrity of the - resulting status. - Toggling of the stati New, Unread, Read and Old is not supported. - These stati are completely ignored. - */ - void toggle( const MessageStatus &other ); - - /* ----- getters ----------------------------------------------------- */ - - /** Check for Unknown status. - @return true if status is unknown. - */ - bool isOfUnknownStatus() const; - - /** Check for New status. Ignored messages are not new. - @return true if status is new. - */ - bool isNew() const; - - /** Check for Unread status. Note that new messages are not unread. - Ignored messages are not unread as well. - @return true if status is unread. - */ - bool isUnread() const; - - /** Check for Read status. Note that ignored messages are read. - @return true if status is read. - */ - bool isRead() const; - - /** Check for Old status. - @return true if status is old. - */ - bool isOld() const; - - /** Check for Deleted status. - @return true if status is deleted. - */ - bool isDeleted() const; - - /** Check for Replied status. - @return true if status is replied. - */ - bool isReplied() const; - - /** Check for Forwarded status. - @return true if status is forwarded. - */ - bool isForwarded() const; - - /** Check for Queued status. - @return true if status is queued. - */ - bool isQueued() const; - - /** Check for Sent status. - @return true if status is sent. - */ - bool isSent() const; - - /** Check for Important status. - @return true if status is important. - */ - bool isImportant() const; - - /** Check for Watched status. - @return true if status is watched. - */ - bool isWatched() const; - - /** Check for Ignored status. - @return true if status is ignored. - */ - bool isIgnored() const; - - /** Check for ToAct status. - @return true if status is action item. - */ - bool isToAct() const; - - /** Check for Spam status. - @return true if status is spam. - */ - bool isSpam() const; - - /** Check for Ham status. - @return true if status is not spam. - */ - bool isHam() const; - - /** Check for Attachment status. - @return true if status indicates an attachment. - */ - bool hasAttachment() const; - - /* ----- setters ----------------------------------------------------- */ - - /** Set the status to new. */ - void setNew(); - - /** Set the status to unread. */ - void setUnread(); - - /** Set the status to read. */ - void setRead(); - - /** Set the status to old. */ - void setOld(); - - /** Set the status for deleted. - @param deleted Set (true) or unset (false) this status flag. - */ - void setDeleted( bool deleted = true ); - - /** Set the status for replied. - @param replied Set (true) or unset (false) this status flag. - */ - void setReplied( bool replied = true ); - - /** Set the status for forwarded. - @param forwarded Set (true) or unset (false) this status flag. - */ - void setForwarded( bool forwarded = true ); - - /** Set the status for queued. - @param queued Set (true) or unset (false) this status flag. - */ - void setQueued( bool queued = true ); - - /** Set the status for sent. - @param sent Set (true) or unset (false) this status flag. - */ - void setSent( bool sent = true ); - - /** Set the status for important. - @param important Set (true) or unset (false) this status flag. - */ - void setImportant( bool important = true ); - - /** Set the status to watched. - @param watched Set (true) or unset (false) this status flag. - */ - void setWatched( bool watched = true ); - - /** Set the status to ignored. - @param ignored Set (true) or unset (false) this status flag. - */ - void setIgnored( bool ignored = true ); - - /** Set the status to action item. - @param toAct Set (true) or unset (false) this status flag. - */ - void setToAct( bool toAct = true ); - - /** Set the status to spam. - @param spam Set (true) or unset (false) this status flag. - */ - void setSpam( bool spam = true ); - - /** Set the status to not spam. - @param ham Set (true) or unset (false) this status flag. - */ - void setHam( bool ham = true ); - - /** Set the status for an attachment. - @param withAttechment Set (true) or unset (false) this status flag. - */ - void setHasAttachment( bool withAttachment = true ); - - /* ----- state representation --------------------------------------- */ - - /** Get the status as a whole e.g. for storage in an index. - Don't manipulte the index via this value, this bypasses - all integrity checks in the setter methods. - @return The status encoded in bits. - */ - qint32 toQInt32() const; - - /** Set the status as a whole e.g. for reading from an index. - Don't manipulte the index via this value, this bypasses - all integrity checks in the setter methods. - @param status The status encoded in bits to be set in this instance. - */ - void fromQInt32( qint32 status ); - - /** Convert the status to a string representation. - @return A string containing coded uppercase letters - which describe the status. - */ - QString getStatusStr() const; - - /** Set the status based on a string representation. - @param aStr The status string to be analyzed. - Normally it is a string obtained using - getStatusStr(). - */ - void setStatusFromStr( QString aStr ); - - /** Convert the status to a string for sorting. - @return A string containing coded lowercase letters - which allows a predefined sorting by status. - */ - QString getSortRank() const; - - /** Get the status as a whole e.g. for storage as IMAP flags. - @return The status encoded in flags. - */ - QSet getStatusFlags() const; - - /** Set the status as a whole e.g. for reading from IMAP flags. - @param status The status encoded in bits to be set in this instance. - */ - void setStatusFromFlags( const QSet &flags ); - - /* ----- static accessors to simple states --------------------------- */ - - /** Return a predefined status initialized as New as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as New. - */ - static MessageStatus statusNew(); - - /** Return a predefined status initialized as Read as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Read. - */ - static MessageStatus statusRead(); - - /** Return a predefined status initialized as Unread as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Unread. - */ - static MessageStatus statusUnread(); - - /** Return a predefined status initialized as New and Unread as is - useful e.g. when searching for unread messages. - @return A reference to a status instance initialized as New | Unread. - */ - static MessageStatus statusNewAndUnread(); - - /** Return a predefined status initialized as Old as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Old. - */ - static MessageStatus statusOld(); - - /** Return a predefined status initialized as Deleted as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Deleted. - */ - static MessageStatus statusDeleted(); - - /** Return a predefined status initialized as Replied as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Replied. - */ - static MessageStatus statusReplied(); - - /** Return a predefined status initialized as Forwarded as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Forwarded. - */ - static MessageStatus statusForwarded(); - - /** Return a predefined status initialized as Queued as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Queued. - */ - static MessageStatus statusQueued(); - - /** Return a predefined status initialized as Sent as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Sent. - */ - static MessageStatus statusSent(); - - /** Return a predefined status initialized as Important as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Important. - */ - static MessageStatus statusImportant(); - - /** Return a predefined status initialized as Watched as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Watched. - */ - static MessageStatus statusWatched(); - - /** Return a predefined status initialized as Ignored as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Ignored. - */ - static MessageStatus statusIgnored(); - - /** Return a predefined status initialized as Action Item as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as ToAct. - */ - static MessageStatus statusToAct(); - - /** Return a predefined status initialized as Spam as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Spam. - */ - static MessageStatus statusSpam(); - - /** Return a predefined status initialized as Ham as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Ham. - */ - static MessageStatus statusHam(); - - /** Return a predefined status initialized as Attachment as is useful - e.g. when providing a state for comparison. - @return A reference to a status instance initialized as Attachment. - */ - static MessageStatus statusHasAttachment(); - - private: - qint32 mStatus; -}; - -} // namespace KPIM - -#endif /*KMAIL_MESSAGESTATUS_H*/ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentcompressjob.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentcompressjob.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentcompressjob.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentcompressjob.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,138 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on KMail code by various authors. + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentcompressjob.h" + +#include + +#include +#include + +#include +#include +#include +#include + +using namespace KPIM; + +class KPIM::AttachmentCompressJob::Private +{ + public: + Private( AttachmentCompressJob *qq ); + + void doStart(); // slot + + AttachmentCompressJob *const q; + AttachmentPart::Ptr originalPart; + AttachmentPart::Ptr compressedPart; + bool compressedPartLarger; +}; + +AttachmentCompressJob::Private::Private( AttachmentCompressJob *qq ) + : q( qq ) + , compressedPartLarger( false ) +{ +} + +void AttachmentCompressJob::Private::doStart() +{ + Q_ASSERT( originalPart ); + QByteArray decoded = originalPart->data(); + + QByteArray array; + QBuffer dev( &array ); + KZip zip( &dev ); + if( !zip.open( QIODevice::WriteOnly ) ) { + q->setError( KJob::UserDefinedError ); + q->setErrorText( i18n( "Could not initiate attachment compression." ) ); + q->emitResult(); + return; + } + + // Compress. + zip.setCompression( KZip::DeflateCompression ); + if( !zip.writeFile( originalPart->name(), QString( /*user*/ ), QString( /*group*/ ), + decoded.data(), decoded.size() ) ) { + q->setError( KJob::UserDefinedError ); + q->setErrorText( i18n( "Could not compress the attachment." ) ); + q->emitResult(); + return; + } + zip.close(); + compressedPartLarger = ( array.size() >= decoded.size() ); + + // Create new part. + Q_ASSERT( compressedPart == 0 ); + compressedPart = AttachmentPart::Ptr( new AttachmentPart ); + compressedPart->setName( originalPart->name() + QString::fromLatin1( ".zip" ) ); // TODO not sure name should be .zipped too + compressedPart->setFileName( originalPart->fileName() + QString::fromLatin1( ".zip" ) ); + compressedPart->setDescription( originalPart->description() ); + compressedPart->setInline( originalPart->isInline() ); + compressedPart->setMimeType( "application/zip" ); + compressedPart->setCompressed( true ); + compressedPart->setEncrypted( originalPart->isEncrypted() ); + compressedPart->setSigned( originalPart->isSigned() ); + compressedPart->setData( array ); + q->emitResult(); // Success. + + // TODO consider adding a copy constructor to AttachmentPart. +} + + + +AttachmentCompressJob::AttachmentCompressJob( const AttachmentPart::Ptr &part, QObject *parent ) + : KJob( parent ) + , d( new Private( this ) ) +{ + d->originalPart = part; +} + +AttachmentCompressJob::~AttachmentCompressJob() +{ + delete d; +} + +void AttachmentCompressJob::start() +{ + QTimer::singleShot( 0, this, SLOT(doStart()) ); +} + +const AttachmentPart::Ptr AttachmentCompressJob::originalPart() const +{ + return d->originalPart; +} + +void AttachmentCompressJob::setOriginalPart( const AttachmentPart::Ptr part ) +{ + d->originalPart = part; +} + +AttachmentPart::Ptr AttachmentCompressJob::compressedPart() const +{ + return d->compressedPart; +} + +bool AttachmentCompressJob::isCompressedPartLarger() const +{ + return d->compressedPartLarger; +} + +#include "attachmentcompressjob.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentcompressjob.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentcompressjob.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentcompressjob.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentcompressjob.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,57 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef KDEPIM_ATTACHMENTCOMPRESSJOB_H +#define KDEPIM_ATTACHMENTCOMPRESSJOB_H + +#include "attachmentpart.h" +#include "messagecore_export.h" + +#include + +namespace KPIM { + +/** +*/ +class MESSAGECORE_EXPORT AttachmentCompressJob : public KJob +{ + Q_OBJECT + + public: + explicit AttachmentCompressJob( const AttachmentPart::Ptr &part, QObject *parent = 0 ); + virtual ~AttachmentCompressJob(); + + virtual void start(); + + const AttachmentPart::Ptr originalPart() const; + void setOriginalPart( const AttachmentPart::Ptr part ); + /// does not delete it unless it failed... + AttachmentPart::Ptr compressedPart() const; + bool isCompressedPartLarger() const; + + private: + class Private; + friend class Private; + Private *const d; + Q_PRIVATE_SLOT( d, void doStart() ) +}; + +} // namespace KPIM + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentfrommimecontentjob.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentfrommimecontentjob.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentfrommimecontentjob.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentfrommimecontentjob.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,93 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on KMail code by: + Copyright (c) 1997 Markus Wuebben + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentfrommimecontentjob.h" + +#include + +#include + +#include "kmime/kmime_content.h" + +using namespace KPIM; +using KMime::Content; + +class KPIM::AttachmentFromMimeContentJob::Private +{ + public: + const Content *mimeContent; + QByteArray data; +}; + + + +AttachmentFromMimeContentJob::AttachmentFromMimeContentJob( const Content *content, QObject *parent ) + : AttachmentLoadJob( parent ) + , d( new Private ) +{ + d->mimeContent = content; +} + +AttachmentFromMimeContentJob::~AttachmentFromMimeContentJob() +{ + delete d; +} + +const Content *AttachmentFromMimeContentJob::mimeContent() const +{ + return d->mimeContent; +} + +void AttachmentFromMimeContentJob::setMimeContent( const Content *content ) +{ + d->mimeContent = content; +} + +void AttachmentFromMimeContentJob::doStart() +{ + // Create the AttachmentPart. + Q_ASSERT( attachmentPart() == 0 ); + AttachmentPart::Ptr part = AttachmentPart::Ptr( new AttachmentPart ); + Content *content = const_cast( d->mimeContent ); + part->setData( content->decodedContent() ); + + // Get the details from the MIME headers. + if( content->contentType( false ) ) { + part->setMimeType( content->contentType()->mimeType() ); + part->setName( content->contentType()->name() ); + } + if( content->contentTransferEncoding( false ) ) { + part->setEncoding( content->contentTransferEncoding()->encoding() ); + } + if( content->contentDisposition( false ) ) { + part->setFileName( content->contentDisposition()->filename() ); + part->setInline( content->contentDisposition()->disposition() == KMime::Headers::CDinline ); + } + if( content->contentDescription( false ) ) { + part->setDescription( content->contentDescription()->asUnicodeString() ); + } + + setAttachmentPart( part ); + emitResult(); // Success. +} + +#include "attachmentfrommimecontentjob.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentfrommimecontentjob.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentfrommimecontentjob.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentfrommimecontentjob.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentfrommimecontentjob.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,56 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef KDEPIM_ATTACHMENTFROMMIMECONTENTJOB_H +#define KDEPIM_ATTACHMENTFROMMIMECONTENTJOB_H + +#include "attachmentloadjob.h" +#include "messagecore_export.h" + +namespace KMime { + class Content; +} + +namespace KPIM { + +/** +*/ +class MESSAGECORE_EXPORT AttachmentFromMimeContentJob : public AttachmentLoadJob +{ + Q_OBJECT + + public: + explicit AttachmentFromMimeContentJob( const KMime::Content *content, QObject *parent = 0 ); + virtual ~AttachmentFromMimeContentJob(); + + const KMime::Content *mimeContent() const; + void setMimeContent( const KMime::Content *content ); + + protected slots: + virtual void doStart(); + + private: + class Private; + friend class Private; + Private *const d; +}; + +} // namespace KPIM + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentfromurljob.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentfromurljob.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentfromurljob.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentfromurljob.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,161 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Parts based on KMail code by various authors. + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentfromurljob.h" + +#include + +#include + +#include +#include +#include +#include +#include + +using namespace KPIM; + +class KPIM::AttachmentFromUrlJob::Private +{ + public: + Private( AttachmentFromUrlJob *qq ); + + void transferJobData( KIO::Job *job, const QByteArray &jobData ); + void transferJobResult( KJob *job ); + + AttachmentFromUrlJob *const q; + KUrl url; + qint64 maxSize; + QByteArray data; +}; + +AttachmentFromUrlJob::Private::Private( AttachmentFromUrlJob *qq ) + : q( qq ) + , maxSize( -1 ) +{ +} + +void AttachmentFromUrlJob::Private::transferJobData( KIO::Job *job, const QByteArray &jobData ) +{ + Q_UNUSED( job ); + data += jobData; + // TODO original code used a QBuffer; why? +} + +void AttachmentFromUrlJob::Private::transferJobResult( KJob *job ) +{ + if( job->error() ) { + // TODO this loses useful stuff from KIO, like detailed error descriptions, causes+solutions, + // ... use UiDelegate somehow? + q->setError( job->error() ); + q->setErrorText( job->errorString() ); + q->emitResult(); + return; + } + + Q_ASSERT( dynamic_cast( job ) ); + KIO::TransferJob *tjob = static_cast( job ); + + // Determine the MIME type and filename of the attachment. + QString mimeType = tjob->mimetype(); + kDebug() << "Mimetype is" << tjob->mimetype(); + QString filename = url.fileName(); + if( filename.isEmpty() ) { + filename = i18nc( "a file called 'unknown.ext'", "unknown%1", + KMimeType::mimeType( mimeType )->mainExtension() ); + } + + // Create the AttachmentPart. + Q_ASSERT( q->attachmentPart() == 0 ); // Not created before. + AttachmentPart::Ptr part = AttachmentPart::Ptr( new AttachmentPart ); + part->setCharset( url.fileEncoding().toLatin1() ); + part->setMimeType( mimeType.toLatin1() ); + part->setName( filename ); + part->setFileName( filename ); + part->setData( data ); + q->setAttachmentPart( part ); + q->emitResult(); // Success. +} + + + +AttachmentFromUrlJob::AttachmentFromUrlJob( const KUrl &url, QObject *parent ) + : AttachmentLoadJob( parent ) + , d( new Private( this ) ) +{ + d->url = url; +} + +AttachmentFromUrlJob::~AttachmentFromUrlJob() +{ + delete d; +} + +KUrl AttachmentFromUrlJob::url() const +{ + return d->url; +} + +void AttachmentFromUrlJob::setUrl( const KUrl &url ) +{ + d->url = url; +} + +qint64 AttachmentFromUrlJob::maximumAllowedSize() const +{ + return d->maxSize; +} + +void AttachmentFromUrlJob::setMaximumAllowedSize( qint64 size ) +{ + d->maxSize = size; +} + +void AttachmentFromUrlJob::doStart() +{ + if( !d->url.isValid() ) { + setError( KJob::UserDefinedError ); + setErrorText( i18n( "\"%1\" not found. Please specify the full path.", d->url.prettyUrl() ) ); + emitResult(); + return; + } + + if( d->maxSize != -1 && d->url.isLocalFile() ) { + const qint64 size = QFileInfo( d->url.toLocalFile() ).size(); + if( size > d->maxSize ) { + setError( KJob::UserDefinedError ); + setErrorText( i18n( "You may not attach files bigger than %1.", + KGlobal::locale()->formatByteSize( d->maxSize ) ) ); + emitResult(); + return; + } + } + + Q_ASSERT( d->data.isEmpty() ); // Not started twice. + KIO::TransferJob *tjob = KIO::get( d->url, KIO::NoReload, + ( uiDelegate() ? KIO::DefaultFlags : KIO::HideProgressInfo ) ); + KIO::Scheduler::scheduleJob( tjob ); + QObject::connect( tjob, SIGNAL(result(KJob*)), this, SLOT(transferJobResult(KJob*)) ); + QObject::connect( tjob, SIGNAL(data(KIO::Job*,QByteArray)), + this, SLOT(transferJobData(KIO::Job*,QByteArray)) ); +} + +#include "attachmentfromurljob.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentfromurljob.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentfromurljob.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentfromurljob.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentfromurljob.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,59 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef KDEPIM_ATTACHMENTFROMURLJOB_H +#define KDEPIM_ATTACHMENTFROMURLJOB_H + +#include "attachmentloadjob.h" +#include "messagecore_export.h" + +#include + +namespace KPIM { + +/** +*/ +class MESSAGECORE_EXPORT AttachmentFromUrlJob : public AttachmentLoadJob +{ + Q_OBJECT + + public: + explicit AttachmentFromUrlJob( const KUrl &url = KUrl(), QObject *parent = 0 ); + virtual ~AttachmentFromUrlJob(); + + KUrl url() const; + void setUrl( const KUrl &url ); + qint64 maximumAllowedSize() const; + void setMaximumAllowedSize( qint64 size ); + + protected slots: + virtual void doStart(); + + private: + class Private; + friend class Private; + Private *const d; + + Q_PRIVATE_SLOT( d, void transferJobData( KIO::Job*, QByteArray ) ) + Q_PRIVATE_SLOT( d, void transferJobResult( KJob* ) ) +}; + +} // namespace KPIM + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentloadjob.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentloadjob.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentloadjob.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentloadjob.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,62 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentloadjob.h" + +#include + +#include + +using namespace KPIM; + +class KPIM::AttachmentLoadJob::Private +{ + public: + AttachmentPart::Ptr part; +}; + + + +AttachmentLoadJob::AttachmentLoadJob( QObject *parent ) + : KJob( parent ) + , d( new Private ) +{ +} + +AttachmentLoadJob::~AttachmentLoadJob() +{ + delete d; +} + +void AttachmentLoadJob::start() +{ + QTimer::singleShot( 0, this, SLOT(doStart()) ); +} + +AttachmentPart::Ptr AttachmentLoadJob::attachmentPart() const +{ + return d->part; +} + +void AttachmentLoadJob::setAttachmentPart( AttachmentPart::Ptr part ) +{ + d->part = part; +} + +#include "attachmentloadjob.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentloadjob.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentloadjob.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentloadjob.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentloadjob.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,58 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef KDEPIM_ATTACHMENTLOADJOB_H +#define KDEPIM_ATTACHMENTLOADJOB_H + +#include "attachmentpart.h" +#include "messagecore_export.h" + +#include + +namespace KPIM { + +/** +*/ +class MESSAGECORE_EXPORT AttachmentLoadJob : public KJob +{ + Q_OBJECT + + public: + explicit AttachmentLoadJob( QObject *parent = 0 ); + virtual ~AttachmentLoadJob(); + + virtual void start(); + + AttachmentPart::Ptr attachmentPart() const; + + protected: + /// for subclasses to set the resulting loaded part. + void setAttachmentPart( AttachmentPart::Ptr part ); + + protected slots: + virtual void doStart() = 0; + + private: + class Private; + Private *const d; +}; + +} // namespace KPIM + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpart.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpart.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpart.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpart.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,215 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentpart.h" + +#include +#include + +#include +#include + +using namespace KPIM; + +uint KPIM::qHash( const KPIM::AttachmentPart::Ptr &ptr ) +{ + return ::qHash( ptr.get() ); +} + +// TODO move to kmime_util? +static qint64 sizeWithEncoding( const QByteArray &data, + KMime::Headers::contentEncoding encoding ) // local +{ + KMime::Content *c = new KMime::Content; + c->setBody( data ); + c->contentTransferEncoding()->setEncoding( encoding ); + int size = c->size(); + delete c; + return size; +} + +class KPIM::AttachmentPart::Private +{ + public: + QString name; + QString fileName; + QString description; + bool isInline; + bool autoEncoding; + KMime::Headers::contentEncoding encoding; + QByteArray charset; + QByteArray mimeType; + bool compressed; + bool toEncrypt; + bool toSign; + QByteArray data; + qint64 size; +}; + +AttachmentPart::AttachmentPart() + : d( new Private ) +{ + d->isInline = false; + d->autoEncoding = true; + d->encoding = KMime::Headers::CE7Bit; + d->compressed = false; + d->toEncrypt = false; + d->toSign = false; + d->size = -1; +} + +AttachmentPart::~AttachmentPart() +{ + delete d; +} + +QString AttachmentPart::name() const +{ + return d->name; +} + +void AttachmentPart::setName( const QString &name ) +{ + d->name = name; +} + +QString AttachmentPart::fileName() const +{ + return d->fileName; +} + +void AttachmentPart::setFileName( const QString &name ) +{ + d->fileName = name; +} + +QString AttachmentPart::description() const +{ + return d->description; +} + +void AttachmentPart::setDescription( const QString &description ) +{ + d->description = description; +} + +bool AttachmentPart::isInline() const +{ + return d->isInline; +} + +void AttachmentPart::setInline( bool inl ) +{ + d->isInline = inl; +} + +bool AttachmentPart::isAutoEncoding() const +{ + return d->autoEncoding; +} + +void AttachmentPart::setAutoEncoding( bool enabled ) +{ + d->autoEncoding = enabled; + if( enabled ) { + d->encoding = KMime::encodingsForData( d->data ).first(); + } + d->size = sizeWithEncoding( d->data, d->encoding ); +} + +KMime::Headers::contentEncoding AttachmentPart::encoding() const +{ + return d->encoding; +} + +void AttachmentPart::setEncoding( KMime::Headers::contentEncoding encoding ) +{ + d->autoEncoding = false; + d->encoding = encoding; + d->size = sizeWithEncoding( d->data, d->encoding ); +} + +QByteArray AttachmentPart::charset() const +{ + return d->charset; +} + +void AttachmentPart::setCharset( const QByteArray &charset ) +{ + d->charset = charset; +} + +QByteArray AttachmentPart::mimeType() const +{ + return d->mimeType; +} + +void AttachmentPart::setMimeType( const QByteArray &mimeType ) +{ + d->mimeType = mimeType; +} + +bool AttachmentPart::isCompressed() const +{ + return d->compressed; +} + +void AttachmentPart::setCompressed( bool compressed ) +{ + d->compressed = compressed; +} + +bool AttachmentPart::isEncrypted() const +{ + return d->toEncrypt; +} + +void AttachmentPart::setEncrypted( bool encrypted ) +{ + d->toEncrypt = encrypted; +} + +bool AttachmentPart::isSigned() const +{ + return d->toSign; +} + +void AttachmentPart::setSigned( bool sign ) +{ + d->toSign = sign; +} + +QByteArray AttachmentPart::data() const +{ + return d->data; +} + +void AttachmentPart::setData( const QByteArray &data ) +{ + d->data = data; + if( d->autoEncoding ) { + d->encoding = KMime::encodingsForData( data ).first(); + }; + d->size = sizeWithEncoding( d->data, d->encoding ); +} + +qint64 AttachmentPart::size() const +{ + return d->size; +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpart.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpart.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpart.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpart.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,90 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef KDEPIM_ATTACHMENTPART_H +#define KDEPIM_ATTACHMENTPART_H + +#include "messagecore_export.h" + +#include + +#include +#include + +#include + +namespace KPIM { + +class MESSAGECORE_EXPORT AttachmentPart +{ + public: + //typedef QList List; + typedef boost::shared_ptr Ptr; + typedef QList List; + + AttachmentPart(); + virtual ~AttachmentPart(); + + /// the name= in Content-Type + QString name() const; + void setName( const QString &name ); + /// the filename= in Content-Disposition + QString fileName() const; + void setFileName( const QString &name ); + QString description() const; + void setDescription( const QString &description ); + // otherwise "attachment" + bool isInline() const; // Perhaps rename to autoDisplay, since the users of + // this class aren't supposed to know MIME? + void setInline( bool inl ); + // default true + bool isAutoEncoding() const; + void setAutoEncoding( bool enabled ); + // only if isAutoEncoding false + KMime::Headers::contentEncoding encoding() const; + void setEncoding( KMime::Headers::contentEncoding encoding ); + QByteArray charset() const; + void setCharset( const QByteArray &charset ); + QByteArray mimeType() const; + void setMimeType( const QByteArray &mimeType ); + bool isCompressed() const; + void setCompressed( bool compressed ); + bool isEncrypted() const; + void setEncrypted( bool encrypted ); + bool isSigned() const; + void setSigned( bool sign ); + QByteArray data() const; + void setData( const QByteArray &data ); + qint64 size() const; + + // TODO outlook-compatible names... + + private: + class Private; + Private *const d; +}; + +// FIXME I don't understand why this doesn't work if I put it outside namespace KPIM. +MESSAGECORE_EXPORT uint qHash( const boost::shared_ptr &ptr ); + +} // namespace KPIM + +Q_DECLARE_METATYPE( KPIM::AttachmentPart::Ptr ) + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpropertiesdialog.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpropertiesdialog.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpropertiesdialog.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpropertiesdialog.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,319 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on KMail code by various authors (kmmsgpartdlg). + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentpropertiesdialog.h" + +#include "attachmentfrommimecontentjob.h" +#include "ui_attachmentpropertiesdialog.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace KPIM; + +class KPIM::AttachmentPropertiesDialog::Private +{ + public: + Private( AttachmentPropertiesDialog *qq ) + : q( qq ) + , readOnly( false ) + { + } + + void init( AttachmentPart::Ptr part, bool readOnly ); + void polishUi(); + void mimeTypeChanged( const QString &type ); // slot + void populateEncodings(); + void populateMimeTypes(); + void populateWhatsThis(); + void loadFromPart(); + void saveToPart(); + + AttachmentPropertiesDialog *const q; + bool readOnly; + AttachmentPart::Ptr part; + Ui::AttachmentPropertiesDialog ui; +}; + +void AttachmentPropertiesDialog::Private::init( AttachmentPart::Ptr part, bool readOnly ) +{ + this->readOnly = readOnly; + this->part = part; + + QWidget *widget = new QWidget( q ); + q->setMainWidget( widget ); + ui.setupUi( widget ); + polishUi(); + q->setModal( true ); + q->showButtonSeparator( true ); + q->setHelp( QString::fromLatin1( "attachments" ) ); + + loadFromPart(); +} + +void AttachmentPropertiesDialog::Private::polishUi() +{ + // Update the icon when the selected mime type changes. + connect( ui.mimeType, SIGNAL(editTextChanged(QString)), + q, SLOT(mimeTypeChanged(QString)) ); + + // Tweak the dialog, depending on whether it is read-only or not. + if( readOnly ) { + ui.mimeType->setEditable( false ); + ui.name->setReadOnly( true ); + ui.description->setReadOnly( true ); + ui.encoding->setEnabled( false ); + ui.autoDisplay->setEnabled( false ); + ui.encrypt->setEnabled( false ); + ui.sign->setEnabled( false ); + + q->setButtons( Ok|Help ); + } else { + populateEncodings(); + populateMimeTypes(); + + q->setButtons( Ok|Cancel|Help ); + } + + q->setDefaultButton( Ok ); + populateWhatsThis(); +} + +void AttachmentPropertiesDialog::Private::mimeTypeChanged( const QString &type ) +{ + KMimeType::Ptr mimeType = KMimeType::mimeType( type, KMimeType::ResolveAliases ); + if( !mimeType.isNull() ) { + ui.mimeIcon->setPixmap( KIconLoader::global()->loadMimeTypeIcon( mimeType->iconName(), + KIconLoader::Desktop ) ); + } else { + ui.mimeIcon->setPixmap( DesktopIcon( "unknown" ) ); + } +} + +void AttachmentPropertiesDialog::Private::populateWhatsThis() +{ + QString msg; + + // FIXME These are such a mess... Make them straightforward and pretty. + + msg = i18n( "

The MIME type of the file:

" + "

Normally, you do not need to touch this setting, since the " + "type of the file is automatically checked; but, sometimes, %1 " + "may not detect the type correctly -- here is where you can fix " + "that.

", KGlobal::mainComponent().aboutData()->programName() ); + ui.mimeType->setWhatsThis( msg ); + + msg = i18n( "

The estimated size of the attachment:

" + "

Note that, in an email message, a binary file encoded with " + "base64 will take up four thirds the actual size of the file.

" ); + ui.size->setWhatsThis( msg ); + + msg = i18n( "

The file name of the part:

" + "

Although this defaults to the name of the attached file, " + "it does not specify the file to be attached; rather, it " + "suggests a file name to be used by the recipient's mail agent " + "when saving the part to disk.

" ); + ui.name->setWhatsThis( msg ); + + msg = i18n( "

A description of the part:

" + "

This is just an informational description of the part, " + "much like the Subject is for the whole message; most " + "mail agents will show this information in their message " + "previews alongside the attachment's icon.

" ); + ui.description->setWhatsThis( msg ); + + msg = i18n( "

The transport encoding of this part:

" + "

Normally, you do not need to change this, since %1 will use " + "a decent default encoding, depending on the MIME type; yet, " + "sometimes, you can significantly reduce the size of the " + "resulting message, e.g. if a PostScript file does not contain " + "binary data, but consists of pure text -- in this case, choosing " + "\"quoted-printable\" over the default \"base64\" will save up " + "to 25% in resulting message size.

", + KGlobal::mainComponent().aboutData()->programName() ); + ui.encoding->setWhatsThis( msg ); + + msg = i18n( "

Check this option if you want to suggest to the " + "recipient the automatic (inline) display of this part in the " + "message preview, instead of the default icon view;

" + "

Technically, this is carried out by setting this part's " + "Content-Disposition header field to \"inline\" " + "instead of the default \"attachment\".

" ); + ui.autoDisplay->setWhatsThis( msg ); + + msg = i18n( "

Check this option if you want this message part to be " + "signed.

" + "

The signature will be made with the key that you associated " + "with the currently-selected identity.

" ); + ui.sign->setWhatsThis( msg ); + + msg = i18n( "

Check this option if you want this message part to be " + "encrypted.

" + "

The part will be encrypted for the recipients of this " + "message.

" ); + ui.encrypt->setWhatsThis( msg ); +} + +void AttachmentPropertiesDialog::Private::populateEncodings() +{ + using namespace KMime; + using namespace KMime::Headers; + + ui.encoding->clear(); + ui.encoding->addItem( nameForEncoding( CE7Bit ), int( CE7Bit ) ); + ui.encoding->addItem( nameForEncoding( CE8Bit ), int( CE8Bit ) ); + ui.encoding->addItem( nameForEncoding( CEquPr ), int( CEquPr ) ); + ui.encoding->addItem( nameForEncoding( CEbase64 ), int( CEbase64 ) ); + + // TODO 8bit should be disabled if it is disabled in Settings. + // Also, if it's a message/* part, base64 and qp should be disabled. + // But since this is a dialog for power users anyway, let them shoot + // themselves in the foot. (The AttachmentJob will fail when they + // try to compose the message.) +} + +void AttachmentPropertiesDialog::Private::populateMimeTypes() +{ + // TODO these are what the old KMMsgPartDialog used. + // Should we use KMimeType::allMimeTypes()? + + QStringList list; + list << QString::fromLatin1( "text/html" ) + << QString::fromLatin1( "text/plain" ) + << QString::fromLatin1( "image/gif" ) + << QString::fromLatin1( "image/jpeg" ) + << QString::fromLatin1( "image/png" ) + << QString::fromLatin1( "application/octet-stream" ) + << QString::fromLatin1( "application/x-gunzip" ) + << QString::fromLatin1( "application/zip" ); + ui.mimeType->addItems( list ); +} + +void AttachmentPropertiesDialog::Private::loadFromPart() +{ + Q_ASSERT( part ); + + ui.mimeType->setCurrentItem( part->mimeType(), true ); + ui.size->setText( KGlobal::locale()->formatByteSize( part->size() ) ); + ui.name->setText( part->name() ); + ui.description->setText( part->description() ); + ui.encoding->setCurrentIndex( int( part->encoding() ) ); + ui.autoDisplay->setChecked( part->isInline() ); + ui.encrypt->setChecked( part->isEncrypted() ); + ui.sign->setChecked( part->isSigned() ); +} + +void AttachmentPropertiesDialog::Private::saveToPart() +{ + Q_ASSERT( part ); + Q_ASSERT( !readOnly ); + + part->setMimeType( ui.mimeType->currentText().toLatin1() ); + part->setName( ui.name->text() ); + // TODO what about fileName? Extra field?? + part->setDescription( ui.description->text() ); + part->setInline( ui.autoDisplay->isChecked() ); + part->setSigned( ui.sign->isChecked() ); + part->setEncrypted( ui.encrypt->isChecked() ); + + if( ui.mimeType->currentText().startsWith( QLatin1String( "message" ) ) && + ui.encoding->itemData( ui.encoding->currentIndex() ) != KMime::Headers::CE7Bit && + ui.encoding->itemData( ui.encoding->currentIndex() ) != KMime::Headers::CE8Bit ) { + kWarning() << "Encoding on message/rfc822 must be \"7bit\" or \"8bit\"."; + } + part->setEncoding( KMime::Headers::contentEncoding( + ui.encoding->itemData( ui.encoding->currentIndex() ).toInt() ) ); +} + +AttachmentPropertiesDialog::AttachmentPropertiesDialog( AttachmentPart::Ptr part, + QWidget *parent, bool readOnly ) + : KDialog( parent ) + , d( new Private( this ) ) +{ + d->init( part, readOnly ); +} + +AttachmentPropertiesDialog::AttachmentPropertiesDialog( const KMime::Content *content, + QWidget *parent, bool readOnly ) + : KDialog( parent ) + , d( new Private( this ) ) +{ + if( !readOnly ) { + kFatal() << "Dialog must be read-only if loading from a KMime::Content."; + } + + AttachmentFromMimeContentJob *ajob = new AttachmentFromMimeContentJob( content, this ); + ajob->exec(); + if( ajob->error() ) { + kError() << "AttachmentFromMimeContentJob failed."; + } + AttachmentPart::Ptr part = ajob->attachmentPart(); + d->init( part, readOnly ); +} + +AttachmentPropertiesDialog::~AttachmentPropertiesDialog() +{ + delete d; +} + +KPIM::AttachmentPart::Ptr AttachmentPropertiesDialog::attachmentPart() const +{ + return d->part; +} + +bool AttachmentPropertiesDialog::isEncryptEnabled() const +{ + return d->ui.encrypt->isEnabled(); +} + +void AttachmentPropertiesDialog::setEncryptEnabled( bool enabled ) +{ + return d->ui.encrypt->setEnabled( enabled ); +} + +bool AttachmentPropertiesDialog::isSignEnabled() const +{ + return d->ui.sign->isEnabled(); +} + +void AttachmentPropertiesDialog::setSignEnabled( bool enabled ) +{ + return d->ui.sign->setEnabled( enabled ); +} + +void AttachmentPropertiesDialog::accept() +{ + if( !d->readOnly ) { + d->saveToPart(); + } + KDialog::accept(); +} + +#include "attachmentpropertiesdialog.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpropertiesdialog.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpropertiesdialog.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpropertiesdialog.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpropertiesdialog.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,71 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on KMail code by various authors (kmmsgpartdlg). + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef KDEPIM_ATTACHMENTPROPERTIESDIALOG_H +#define KDEPIM_ATTACHMENTPROPERTIESDIALOG_H + +#include "attachmentpart.h" +#include "messagecore_export.h" + +#include + +namespace KPIM { + +class MESSAGECORE_EXPORT AttachmentPropertiesDialog: public KDialog +{ + Q_OBJECT + + public: + explicit AttachmentPropertiesDialog( KPIM::AttachmentPart::Ptr part, + QWidget *parent = 0, bool readOnly = false ); + + /** + This converts the KMime::Content to an AttachmentPart. Therefore, saving + the changes to the KMime::Content is not supported, and readOnly must + be true. + */ + explicit AttachmentPropertiesDialog( const KMime::Content *content, + QWidget *parent = 0, bool readOnly = true ); + virtual ~AttachmentPropertiesDialog(); + + KPIM::AttachmentPart::Ptr attachmentPart() const; + + bool isEncryptEnabled() const; + /** Sets whether or not this attachment can be encrypted */ + void setEncryptEnabled( bool enabled ); + bool isSignEnabled() const; + /** Sets whether or not this attachment can be signed */ + void setSignEnabled( bool enabled ); + + public slots: + /* reimpl */ + virtual void accept(); + + private: + class Private; + Private *const d; + + Q_PRIVATE_SLOT( d, void mimeTypeChanged( const QString& ) ) +}; + +} // namespace KMail + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpropertiesdialog.ui /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpropertiesdialog.ui --- kde-nightly-kdepim-20091006+svn1032120/messagecore/attachmentpropertiesdialog.ui 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/attachmentpropertiesdialog.ui 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,227 @@ + + + AttachmentPropertiesDialog + + + + 0 + 0 + 371 + 252 + + + + Attachment Properties + + + + + + + + + + + 0 + 0 + + + + Type: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + mimeType + + + + + + + + + + 0 + 0 + + + + true + + + + + + + pretty icon + + + + + + + + + + 0 + 0 + + + + Size: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + size goes here + + + + + + + + + + 0 + 0 + + + + Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + name + + + + + + + + + false + + + + + + + + + + 0 + 0 + + + + Description: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + description + + + + + + + + + true + + + + + + + + + + 0 + 0 + + + + Encoding: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + encoding + + + + + + + + + + + + Suggest automatic display + + + + + + + Encrypt this attachment + + + + + + + Sign this attachment + + + + + + + + + Qt::Vertical + + + + 20 + 31 + + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+ + KComboBox + QComboBox +
kcombobox.h
+
+
+ + +
diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/messagecore/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/CMakeLists.txt 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,40 @@ +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) + +add_definitions(-DKDE_DEFAULT_DEBUG_AREA=5300) + +add_subdirectory(tests) + +include_directories( ${Boost_INCLUDE_DIR} ) + +########### next target ############### + +set(messagecore_LIB_SRCS + attachmentpart.cpp + attachmentcompressjob.cpp + attachmentloadjob.cpp + attachmentfromurljob.cpp + attachmentfrommimecontentjob.cpp + attachmentpropertiesdialog.cpp + messagestatus.cpp +) + +kde4_add_ui_files(messagecore_LIB_SRCS + attachmentpropertiesdialog.ui +) + +kde4_add_library(messagecore SHARED ${messagecore_LIB_SRCS}) + +target_link_libraries(messagecore + ${KDEPIMLIBS_KMIME_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KIO_LIBS} +) + +target_link_libraries(messagecore LINK_INTERFACE_LIBRARIES + ${KDEPIMLIBS_KMIME_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KIO_LIBS} +) + +set_target_properties(messagecore PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) +install(TARGETS messagecore ${INSTALL_TARGETS_DEFAULT_ARGS}) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/messagecore_export.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/messagecore_export.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/messagecore_export.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/messagecore_export.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,35 @@ +/* + Copyright (c) 2009 Kevin Ottens + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef MESSAGECORE_CORELIST_EXPORT_H +#define MESSAGECORE_CORELIST_EXPORT_H + +#include + +#ifndef MESSAGECORE_EXPORT +# if defined(MAKE_MESSAGECORE_LIB) + /* We are building this library */ +# define MESSAGECORE_EXPORT KDE_EXPORT +# else + /* We are using this library */ +# define MESSAGECORE_EXPORT KDE_IMPORT +# endif +#endif + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/Messages.sh /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/Messages.sh --- kde-nightly-kdepim-20091006+svn1032120/messagecore/Messages.sh 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/Messages.sh 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT *.cpp -o $podir/libmessagecore.pot diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/messagestatus.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/messagestatus.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/messagestatus.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/messagestatus.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,799 @@ +/* + This file is part of KDEPIM. + Copyright (c) 2003 Andreas Gungl + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "messagestatus.h" + +#include +#include + +using namespace KPIM; + +/** The message status format. These can be or'd together. + Note, that the KMMsgStatusIgnored implies the + status to be Read even if the flags are set + to Unread or New. This is done in isRead() + and related getters. So we can preserve the state + when switching a thread to Ignored and back. */ +enum MsgStatus { + KMMsgStatusUnknown = 0x00000000, + KMMsgStatusNew = 0x00000001, + KMMsgStatusUnread = 0x00000002, + KMMsgStatusRead = 0x00000004, + KMMsgStatusOld = 0x00000008, + KMMsgStatusDeleted = 0x00000010, + KMMsgStatusReplied = 0x00000020, + KMMsgStatusForwarded = 0x00000040, + KMMsgStatusQueued = 0x00000080, + KMMsgStatusSent = 0x00000100, + KMMsgStatusFlag = 0x00000200, // flag means important + KMMsgStatusWatched = 0x00000400, + KMMsgStatusIgnored = 0x00000800, // forces isRead() + KMMsgStatusToAct = 0x00001000, + KMMsgStatusSpam = 0x00002000, + KMMsgStatusHam = 0x00004000, + KMMsgStatusHasAttach = 0x00008000 +}; + +MessageStatus::MessageStatus() +{ + mStatus = KMMsgStatusUnknown; +} + +MessageStatus &MessageStatus::operator = ( const MessageStatus &other ) +{ + mStatus = other.mStatus; + return *this; +} + +bool MessageStatus::operator == ( const MessageStatus &other ) const +{ + return ( mStatus == other.mStatus ); +} + +bool MessageStatus::operator != ( const MessageStatus &other ) const +{ + return ( mStatus != other.mStatus ); +} + +bool MessageStatus::operator & ( const MessageStatus &other ) const +{ + return ( mStatus & other.mStatus ); +} + +void MessageStatus::clear() +{ + mStatus = KMMsgStatusUnknown; +} + +void MessageStatus::set( const MessageStatus &other ) +{ + // Those stati are exclusive, but we have to lock at the + // internal representation because Ignored can manipulate + // the result of the getter methods. + if ( other.mStatus & KMMsgStatusNew ) { + setNew(); + } + if ( other.mStatus & KMMsgStatusUnread ) { + setUnread(); + } + if ( other.mStatus & KMMsgStatusRead ) { + setRead(); + } + if ( other.mStatus & KMMsgStatusOld ) { + setOld(); + } + + if ( other.isDeleted() ) { + setDeleted(); + } + if ( other.isReplied() ) { + setReplied(); + } + if ( other.isForwarded() ) { + setForwarded(); + } + if ( other.isQueued() ) { + setQueued(); + } + if ( other.isSent() ) { + setSent(); + } + if ( other.isImportant() ) { + setImportant(); + } + + if ( other.isWatched() ) { + setWatched(); + } + if ( other.isIgnored() ) { + setIgnored(); + } + if ( other.isToAct() ) { + setToAct(); + } + if ( other.isSpam() ) { + setSpam(); + } + if ( other.isHam() ) { + setHam(); + } + if ( other.hasAttachment() ) { + setHasAttachment(); + } +} + +void MessageStatus::toggle( const MessageStatus &other ) +{ + if ( other.isDeleted() ) { + setDeleted( !( mStatus & KMMsgStatusDeleted ) ); + } + if ( other.isReplied() ) { + setReplied( !( mStatus & KMMsgStatusReplied ) ); + } + if ( other.isForwarded() ) { + setForwarded( !( mStatus & KMMsgStatusForwarded ) ); + } + if ( other.isQueued() ) { + setQueued( !( mStatus & KMMsgStatusQueued ) ); + } + if ( other.isSent() ) { + setSent( !( mStatus & KMMsgStatusSent ) ); + } + if ( other.isImportant() ) { + setImportant( !( mStatus & KMMsgStatusFlag ) ); + } + + if ( other.isWatched() ) { + setWatched( !( mStatus & KMMsgStatusWatched ) ); + } + if ( other.isIgnored() ) { + setIgnored( !( mStatus & KMMsgStatusIgnored ) ); + } + if ( other.isToAct() ) { + setToAct( !( mStatus & KMMsgStatusToAct ) ); + } + if ( other.isSpam() ) { + setSpam( !( mStatus & KMMsgStatusSpam ) ); + } + if ( other.isHam() ) { + setHam( !( mStatus & KMMsgStatusHam ) ); + } + if ( other.hasAttachment() ) { + setHasAttachment( !( mStatus & KMMsgStatusHasAttach ) ); + } +} + +bool MessageStatus::isOfUnknownStatus() const +{ + return ( mStatus == KMMsgStatusUnknown ); +} + +bool MessageStatus::isNew() const +{ + return ( mStatus & KMMsgStatusNew && !( mStatus & KMMsgStatusIgnored ) ); +} + +bool MessageStatus::isUnread() const +{ + return ( mStatus & KMMsgStatusUnread && !( mStatus & KMMsgStatusIgnored ) ); +} + +bool MessageStatus::isRead() const +{ + return ( mStatus & KMMsgStatusRead || mStatus & KMMsgStatusIgnored ); +} + +bool MessageStatus::isOld() const +{ + return ( mStatus & KMMsgStatusOld ); +} + +bool MessageStatus::isDeleted() const +{ + return ( mStatus & KMMsgStatusDeleted ); +} + +bool MessageStatus::isReplied() const +{ + return ( mStatus & KMMsgStatusReplied ); +} + +bool MessageStatus::isForwarded() const +{ + return ( mStatus & KMMsgStatusForwarded ); +} + +bool MessageStatus::isQueued() const +{ + return ( mStatus & KMMsgStatusQueued ); +} + +bool MessageStatus::isSent() const +{ + return ( mStatus & KMMsgStatusSent ); +} + +bool MessageStatus::isImportant() const +{ + return ( mStatus & KMMsgStatusFlag ); +} + +bool MessageStatus::isWatched() const +{ + return ( mStatus & KMMsgStatusWatched ); +} + +bool MessageStatus::isIgnored() const +{ + return ( mStatus & KMMsgStatusIgnored ); +} + +bool MessageStatus::isToAct() const +{ + return ( mStatus & KMMsgStatusToAct ); +} + +bool MessageStatus::isSpam() const +{ + return ( mStatus & KMMsgStatusSpam ); +} + +bool MessageStatus::isHam() const +{ + return ( mStatus & KMMsgStatusHam ); +} + +bool MessageStatus::hasAttachment() const +{ + return ( mStatus & KMMsgStatusHasAttach ); +} + +void MessageStatus::setNew() +{ + // new overrides old and read + mStatus &= ~KMMsgStatusOld; + mStatus &= ~KMMsgStatusRead; + mStatus &= ~KMMsgStatusUnread; + mStatus |= KMMsgStatusNew; +} + +void MessageStatus::setUnread() +{ + // unread overrides read + mStatus &= ~KMMsgStatusOld; + mStatus &= ~KMMsgStatusRead; + mStatus &= ~KMMsgStatusNew; + mStatus |= KMMsgStatusUnread; +} + +void MessageStatus::setRead() +{ + // Unset unread and new, set read + mStatus &= ~KMMsgStatusUnread; + mStatus &= ~KMMsgStatusNew; + mStatus |= KMMsgStatusRead; +} + +void MessageStatus::setOld() +{ + // old can't be new or unread + mStatus &= ~KMMsgStatusNew; + mStatus &= ~KMMsgStatusUnread; + mStatus |= KMMsgStatusOld; +} + +void MessageStatus::setDeleted( bool deleted ) +{ + if ( deleted ) { + mStatus |= KMMsgStatusDeleted; + } else { + mStatus &= ~KMMsgStatusDeleted; + } +} + +void MessageStatus::setReplied( bool replied ) +{ + if ( replied ) { + mStatus |= KMMsgStatusReplied; + } else { + mStatus &= ~KMMsgStatusReplied; + } +} + +void MessageStatus::setForwarded( bool forwarded ) +{ + if ( forwarded ) { + mStatus |= KMMsgStatusForwarded; + } else { + mStatus &= ~KMMsgStatusForwarded; + } +} + +void MessageStatus::setQueued( bool queued ) +{ + if ( queued ) { + mStatus |= KMMsgStatusQueued; + } else { + mStatus &= ~KMMsgStatusQueued; + } +} + +void MessageStatus::setSent( bool sent ) +{ + if ( sent ) { + mStatus &= ~KMMsgStatusQueued; + // FIXME to be discussed if sent messages are Read + mStatus &= ~KMMsgStatusUnread; + mStatus &= ~KMMsgStatusNew; + mStatus |= KMMsgStatusSent; + } else { + mStatus &= ~KMMsgStatusSent; + } +} + +void MessageStatus::setImportant( bool important ) +{ + if ( important ) { + mStatus |= KMMsgStatusFlag; + } else { + mStatus &= ~KMMsgStatusFlag; + } +} + +// Watched and ignored are mutually exclusive +void MessageStatus::setWatched( bool watched ) +{ + if ( watched ) { + mStatus &= ~KMMsgStatusIgnored; + mStatus |= KMMsgStatusWatched; + } else { + mStatus &= ~KMMsgStatusWatched; + } +} + +void MessageStatus::setIgnored( bool ignored ) +{ + if ( ignored ) { + mStatus &= ~KMMsgStatusWatched; + mStatus |= KMMsgStatusIgnored; + } else { + mStatus &= ~KMMsgStatusIgnored; + } +} + +void MessageStatus::setToAct( bool toAct ) +{ + if ( toAct ) { + mStatus |= KMMsgStatusToAct; + } else { + mStatus &= ~KMMsgStatusToAct; + } +} + +// Ham and Spam are mutually exclusive +void MessageStatus::setSpam( bool spam ) +{ + if ( spam ) { + mStatus &= ~KMMsgStatusHam; + mStatus |= KMMsgStatusSpam; + } else { + mStatus &= ~KMMsgStatusSpam; + } +} + +void MessageStatus::setHam( bool ham ) +{ + if ( ham ) { + mStatus &= ~KMMsgStatusSpam; + mStatus |= KMMsgStatusHam; + } else { + mStatus &= ~KMMsgStatusHam; + } +} + +void MessageStatus::setHasAttachment( bool withAttachment ) +{ + if ( withAttachment ) { + mStatus |= KMMsgStatusHasAttach; + } else { + mStatus &= ~KMMsgStatusHasAttach; + } +} + +qint32 MessageStatus::toQInt32() const +{ + return mStatus; +} + +void MessageStatus::fromQInt32( qint32 status ) +{ + mStatus = status; +} + +QString MessageStatus::getStatusStr() const +{ + QString sstr; + if ( mStatus & KMMsgStatusNew ) { + sstr += 'N'; + } + if ( mStatus & KMMsgStatusUnread ) { + sstr += 'U'; + } + if ( mStatus & KMMsgStatusOld ) { + sstr += 'O'; + } + if ( mStatus & KMMsgStatusRead ) { + sstr += 'R'; + } + if ( mStatus & KMMsgStatusDeleted ) { + sstr += 'D'; + } + if ( mStatus & KMMsgStatusReplied ) { + sstr += 'A'; + } + if ( mStatus & KMMsgStatusForwarded ) { + sstr += 'F'; + } + if ( mStatus & KMMsgStatusQueued ) { + sstr += 'Q'; + } + if ( mStatus & KMMsgStatusToAct ) { + sstr += 'K'; + } + if ( mStatus & KMMsgStatusSent ) { + sstr += 'S'; + } + if ( mStatus & KMMsgStatusFlag ) { + sstr += 'G'; + } + if ( mStatus & KMMsgStatusWatched ) { + sstr += 'W'; + } + if ( mStatus & KMMsgStatusIgnored ) { + sstr += 'I'; + } + if ( mStatus & KMMsgStatusSpam ) { + sstr += 'P'; + } + if ( mStatus & KMMsgStatusHam ) { + sstr += 'H'; + } + if ( mStatus & KMMsgStatusHasAttach ) { + sstr += 'T'; + } + + return sstr; +} + +void MessageStatus::setStatusFromStr( const QString& aStr ) +{ + mStatus = KMMsgStatusUnknown; + + if ( aStr.contains( 'N' ) ) { + setNew(); + } + if ( aStr.contains( 'U' ) ) { + setUnread(); + } + if ( aStr.contains( 'O' ) ) { + setOld(); + } + if ( aStr.contains( 'R' ) ) { + setRead(); + } + if ( aStr.contains( 'D' ) ) { + setDeleted(); + } + if ( aStr.contains( 'A' ) ) { + setReplied(); + } + if ( aStr.contains( 'F' ) ) { + setForwarded(); + } + if ( aStr.contains( 'Q' ) ) { + setQueued(); + } + if ( aStr.contains( 'K' ) ) { + setToAct(); + } + if ( aStr.contains( 'S' ) ) { + setSent(); + } + if ( aStr.contains( 'G' ) ) { + setImportant(); + } + if ( aStr.contains( 'W' ) ) { + setWatched(); + } + if ( aStr.contains( 'I' ) ) { + setIgnored(); + } + if ( aStr.contains( 'P' ) ) { + setSpam(); + } + if ( aStr.contains( 'H' ) ) { + setHam(); + } + if ( aStr.contains( 'T' ) ) { + setHasAttachment(); + } + if ( aStr.contains( 'C' ) ) { + setHasAttachment( false ); + } +} + +QString MessageStatus::getSortRank() const +{ + QString sstr = "bcbbbbbbbb"; + + // put watched ones first, then normal ones, ignored ones last + if ( mStatus & KMMsgStatusWatched ) { + sstr[0] = 'a'; + } + if ( mStatus & KMMsgStatusIgnored ) { + sstr[0] = 'c'; + } + + // Second level. One of new, old, read, unread + if ( mStatus & KMMsgStatusNew ) { + sstr[1] = 'a'; + } + if ( mStatus & KMMsgStatusUnread ) { + sstr[1] = 'b'; + } + //if ( mStatus & KMMsgStatusOld ) { + // sstr[1] = 'c'; + //} + //if ( mStatus & KMMsgStatusRead ) { + // sstr[1] = 'c'; + //} + + // Third level. In somewhat arbitrary order. + if ( mStatus & KMMsgStatusDeleted ) { + sstr[2] = 'a'; + } + if ( mStatus & KMMsgStatusFlag ) { + sstr[3] = 'a'; + } + if ( mStatus & KMMsgStatusReplied ) { + sstr[4] = 'a'; + } + if ( mStatus & KMMsgStatusForwarded ) { + sstr[5] = 'a'; + } + if ( mStatus & KMMsgStatusQueued ) { + sstr[6] = 'a'; + } + if ( mStatus & KMMsgStatusSent ) { + sstr[7] = 'a'; + } + if ( mStatus & KMMsgStatusHam ) { + sstr[8] = 'a'; + } + if ( mStatus & KMMsgStatusSpam ) { + sstr[8] = 'c'; + } + if ( mStatus & KMMsgStatusToAct ) { + sstr[9] = 'a'; + } + + return sstr; +} + +QSet MessageStatus::getStatusFlags() const +{ + QSet flags; + + // Non handled status: + // * KMMsgStatusQueued + // * KMMsgStatusSent + // * KMMsgStatusSpam + // * KMMsgStatusHam + // * KMMsgStatusHasAttach + + if ( mStatus & KMMsgStatusDeleted ) { + flags+= "\\DELETED"; + } else { + if ( mStatus & ( KMMsgStatusOld | KMMsgStatusRead ) ) + flags+= "\\SEEN "; + if ( mStatus & KMMsgStatusReplied ) + flags+= "\\ANSWERED "; + if ( mStatus & KMMsgStatusFlag ) + flags+= "\\FLAGGED "; + // non standard flags + if ( mStatus & KMMsgStatusForwarded ) + flags+= "$FORWARDED "; + if ( mStatus & KMMsgStatusToAct ) + flags+= "$TODO "; + if ( mStatus & KMMsgStatusWatched ) + flags+= "$WATCHED "; + if ( mStatus & KMMsgStatusIgnored ) + flags+= "$IGNORED "; + } + + return flags; +} + +void MessageStatus::setStatusFromFlags( const QSet &flags ) +{ + mStatus = KMMsgStatusUnknown; + setNew(); + + // Non handled status: + // * KMMsgStatusQueued + // * KMMsgStatusSent + // * KMMsgStatusSpam + // * KMMsgStatusHam + // * KMMsgStatusHasAttach + + foreach ( const QByteArray &flag, flags ) { + if ( flag.toUpper() == QByteArray( "\\DELETED" ) ) { + setDeleted(); + } else if ( flag.toUpper() == QByteArray( "\\SEEN" ) ) { + setRead(); + } else if ( flag.toUpper() == QByteArray( "\\ANSWERED" ) ) { + setReplied(); + } else if ( flag.toUpper() == QByteArray( "\\FLAGGED" ) ) { + setImportant(); + + // non standard flags + } else if ( flag.toUpper() == QByteArray( "$FORWARDED" ) ) { + setForwarded(); + } else if ( flag.toUpper() == QByteArray( "$TODO" ) ) { + setToAct(); + } else if ( flag.toUpper() == QByteArray( "$WATCHED" ) ) { + setWatched(); + } else if ( flag.toUpper() == QByteArray( "$IGNORED" ) ) { + setIgnored(); + } else { + kWarning() << "Unknown flag:" << flag; + } + } +} + +MessageStatus MessageStatus::statusNew() +{ + MessageStatus st; + st.setNew(); + return st; +} + +MessageStatus MessageStatus::statusRead() +{ + MessageStatus st; + st.setRead(); + return st; +} + +MessageStatus MessageStatus::statusUnread() +{ + MessageStatus st; + st.setUnread(); + return st; +} + +MessageStatus MessageStatus::statusNewAndUnread() +{ + MessageStatus st; + // set the "new and unread" pseudo status; we have to set the internal + // representation directly because new and unread are mutually exclusive + st.fromQInt32( statusNew().toQInt32() | statusUnread().toQInt32() ); + return st; +} + +MessageStatus MessageStatus::statusOld() +{ + MessageStatus st; + st.setOld(); + return st; +} + +MessageStatus MessageStatus::statusDeleted() +{ + MessageStatus st; + st.setDeleted(); + return st; +} + +MessageStatus MessageStatus::statusReplied() +{ + MessageStatus st; + st.setReplied(); + return st; +} + +MessageStatus MessageStatus::statusForwarded() +{ + MessageStatus st; + st.setForwarded(); + return st; +} + +MessageStatus MessageStatus::statusQueued() +{ + MessageStatus st; + st.setQueued(); + return st; +} + +MessageStatus MessageStatus::statusSent() +{ + MessageStatus st; + st.setSent(); + return st; +} + +MessageStatus MessageStatus::statusImportant() +{ + MessageStatus st; + st.setImportant(); + return st; +} + +MessageStatus MessageStatus::statusWatched() +{ + MessageStatus st; + st.setWatched(); + return st; +} + +MessageStatus MessageStatus::statusIgnored() +{ + MessageStatus st; + st.setIgnored(); + return st; +} + +MessageStatus MessageStatus::statusToAct() +{ + MessageStatus st; + st.setToAct(); + return st; +} + +MessageStatus MessageStatus::statusSpam() +{ + MessageStatus st; + st.setSpam(); + return st; +} + +MessageStatus MessageStatus::statusHam() +{ + MessageStatus st; + st.setHam(); + return st; +} + +MessageStatus MessageStatus::statusHasAttachment() +{ + MessageStatus st; + st.setHasAttachment(); + return st; +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/messagestatus.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/messagestatus.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/messagestatus.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/messagestatus.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,419 @@ +/* -*- mode: C++ -*- + This file is part of KDEPIM. + Copyright (c) 2005 Andreas Gungl + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ +#ifndef KDEPIM_MESSAGESTATUS_H +#define KDEPIM_MESSAGESTATUS_H + +#include + +#include "messagecore_export.h" + +class QString; + +namespace KPIM { + +//--------------------------------------------------------------------------- +/** + @short KDEPIM Message Status. + @author Andreas Gungl + + The class encapsulates the handling of the different flags + which describe the status of a message. + The flags itself are not intended to be used outside this class. + + In the status pairs Watched/Ignored and Spam/Ham, there both + values can't be set at the same time, however they can + be unset at the same time. + + The stati New/Unread/Read/Old are mutually exclusive. +*/ +class MESSAGECORE_EXPORT MessageStatus +{ + public: + /** Constructor - sets status initially to unknown. */ + MessageStatus(); + + /** Assign the status from another instance. The internal + representation is identical afterwards, i.e. a comparison + by operator == will return true. + */ + MessageStatus &operator = ( const MessageStatus &other ); + + /** Compare the status with that from another instance. + @return true if the stati are equal, false if different. + */ + bool operator == ( const MessageStatus &other ) const; + + /** Compare the status with that from another instance. + @return true if the stati are equal, false if different. + */ + bool operator != ( const MessageStatus &other ) const; + + /** Check, if some of the flags in the status match + with those flags from another instance. + @return true if at least one flag is set in both stati. + */ + bool operator & ( const MessageStatus &other ) const; + + /** Clear all status flags, this resets to unknown. */ + void clear(); + + /** Set / add stati described by another MessageStatus object. + This can be used to merge in multiple stati at once without + using the single setter methods. + However, internally the setters are used anyway to ensure the + integrity of the resulting status. + */ + void set( const MessageStatus &other ); + + /** Toggle one or more stati described by another MessageStatus object. + Internally the setters are used to ensure the integrity of the + resulting status. + Toggling of the stati New, Unread, Read and Old is not supported. + These stati are completely ignored. + */ + void toggle( const MessageStatus &other ); + + /* ----- getters ----------------------------------------------------- */ + + /** Check for Unknown status. + @return true if status is unknown. + */ + bool isOfUnknownStatus() const; + + /** Check for New status. Ignored messages are not new. + @return true if status is new. + */ + bool isNew() const; + + /** Check for Unread status. Note that new messages are not unread. + Ignored messages are not unread as well. + @return true if status is unread. + */ + bool isUnread() const; + + /** Check for Read status. Note that ignored messages are read. + @return true if status is read. + */ + bool isRead() const; + + /** Check for Old status. + @return true if status is old. + */ + bool isOld() const; + + /** Check for Deleted status. + @return true if status is deleted. + */ + bool isDeleted() const; + + /** Check for Replied status. + @return true if status is replied. + */ + bool isReplied() const; + + /** Check for Forwarded status. + @return true if status is forwarded. + */ + bool isForwarded() const; + + /** Check for Queued status. + @return true if status is queued. + */ + bool isQueued() const; + + /** Check for Sent status. + @return true if status is sent. + */ + bool isSent() const; + + /** Check for Important status. + @return true if status is important. + */ + bool isImportant() const; + + /** Check for Watched status. + @return true if status is watched. + */ + bool isWatched() const; + + /** Check for Ignored status. + @return true if status is ignored. + */ + bool isIgnored() const; + + /** Check for ToAct status. + @return true if status is action item. + */ + bool isToAct() const; + + /** Check for Spam status. + @return true if status is spam. + */ + bool isSpam() const; + + /** Check for Ham status. + @return true if status is not spam. + */ + bool isHam() const; + + /** Check for Attachment status. + @return true if status indicates an attachment. + */ + bool hasAttachment() const; + + /* ----- setters ----------------------------------------------------- */ + + /** Set the status to new. */ + void setNew(); + + /** Set the status to unread. */ + void setUnread(); + + /** Set the status to read. */ + void setRead(); + + /** Set the status to old. */ + void setOld(); + + /** Set the status for deleted. + @param deleted Set (true) or unset (false) this status flag. + */ + void setDeleted( bool deleted = true ); + + /** Set the status for replied. + @param replied Set (true) or unset (false) this status flag. + */ + void setReplied( bool replied = true ); + + /** Set the status for forwarded. + @param forwarded Set (true) or unset (false) this status flag. + */ + void setForwarded( bool forwarded = true ); + + /** Set the status for queued. + @param queued Set (true) or unset (false) this status flag. + */ + void setQueued( bool queued = true ); + + /** Set the status for sent. + @param sent Set (true) or unset (false) this status flag. + */ + void setSent( bool sent = true ); + + /** Set the status for important. + @param important Set (true) or unset (false) this status flag. + */ + void setImportant( bool important = true ); + + /** Set the status to watched. + @param watched Set (true) or unset (false) this status flag. + */ + void setWatched( bool watched = true ); + + /** Set the status to ignored. + @param ignored Set (true) or unset (false) this status flag. + */ + void setIgnored( bool ignored = true ); + + /** Set the status to action item. + @param toAct Set (true) or unset (false) this status flag. + */ + void setToAct( bool toAct = true ); + + /** Set the status to spam. + @param spam Set (true) or unset (false) this status flag. + */ + void setSpam( bool spam = true ); + + /** Set the status to not spam. + @param ham Set (true) or unset (false) this status flag. + */ + void setHam( bool ham = true ); + + /** Set the status for an attachment. + @param withAttechment Set (true) or unset (false) this status flag. + */ + void setHasAttachment( bool withAttachment = true ); + + /* ----- state representation --------------------------------------- */ + + /** Get the status as a whole e.g. for storage in an index. + Don't manipulte the index via this value, this bypasses + all integrity checks in the setter methods. + @return The status encoded in bits. + */ + qint32 toQInt32() const; + + /** Set the status as a whole e.g. for reading from an index. + Don't manipulte the index via this value, this bypasses + all integrity checks in the setter methods. + @param status The status encoded in bits to be set in this instance. + */ + void fromQInt32( qint32 status ); + + /** Convert the status to a string representation. + @return A string containing coded uppercase letters + which describe the status. + */ + QString getStatusStr() const; + + /** Set the status based on a string representation. + @param aStr The status string to be analyzed. + Normally it is a string obtained using + getStatusStr(). + */ + void setStatusFromStr( const QString &aStr ); + + /** Convert the status to a string for sorting. + @return A string containing coded lowercase letters + which allows a predefined sorting by status. + */ + QString getSortRank() const; + + /** Get the status as a whole e.g. for storage as IMAP flags. + @return The status encoded in flags. + */ + QSet getStatusFlags() const; + + /** Set the status as a whole e.g. for reading from IMAP flags. + @param status The status encoded in bits to be set in this instance. + */ + void setStatusFromFlags( const QSet &flags ); + + /* ----- static accessors to simple states --------------------------- */ + + /** Return a predefined status initialized as New as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as New. + */ + static MessageStatus statusNew(); + + /** Return a predefined status initialized as Read as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Read. + */ + static MessageStatus statusRead(); + + /** Return a predefined status initialized as Unread as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Unread. + */ + static MessageStatus statusUnread(); + + /** Return a predefined status initialized as New and Unread as is + useful e.g. when searching for unread messages. + @return A reference to a status instance initialized as New | Unread. + */ + static MessageStatus statusNewAndUnread(); + + /** Return a predefined status initialized as Old as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Old. + */ + static MessageStatus statusOld(); + + /** Return a predefined status initialized as Deleted as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Deleted. + */ + static MessageStatus statusDeleted(); + + /** Return a predefined status initialized as Replied as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Replied. + */ + static MessageStatus statusReplied(); + + /** Return a predefined status initialized as Forwarded as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Forwarded. + */ + static MessageStatus statusForwarded(); + + /** Return a predefined status initialized as Queued as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Queued. + */ + static MessageStatus statusQueued(); + + /** Return a predefined status initialized as Sent as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Sent. + */ + static MessageStatus statusSent(); + + /** Return a predefined status initialized as Important as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Important. + */ + static MessageStatus statusImportant(); + + /** Return a predefined status initialized as Watched as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Watched. + */ + static MessageStatus statusWatched(); + + /** Return a predefined status initialized as Ignored as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Ignored. + */ + static MessageStatus statusIgnored(); + + /** Return a predefined status initialized as Action Item as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as ToAct. + */ + static MessageStatus statusToAct(); + + /** Return a predefined status initialized as Spam as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Spam. + */ + static MessageStatus statusSpam(); + + /** Return a predefined status initialized as Ham as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Ham. + */ + static MessageStatus statusHam(); + + /** Return a predefined status initialized as Attachment as is useful + e.g. when providing a state for comparison. + @return A reference to a status instance initialized as Attachment. + */ + static MessageStatus statusHasAttachment(); + + private: + qint32 mStatus; +}; + +} // namespace KPIM + +#endif /*KMAIL_MESSAGESTATUS_H*/ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/README /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/README --- kde-nightly-kdepim-20091006+svn1032120/messagecore/README 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/README 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,12 @@ +What should be put here? +======================== + +Stuff here needs to comply with at least these rules (additionally to all the other ones that apply to all code): +- no dependencies on legacy libs (Qt3/KDE3 support, kresources, libkdepim) +- no dependencies on: + - libmessagelist + - libmessageviewer + - libmessagecomposer +- used by at least one of the above listed libs +- used by at least one other component (most commonly a second one of the above listed libs) + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentcompressjobtest.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentcompressjobtest.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentcompressjobtest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentcompressjobtest.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,107 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentcompressjobtest.h" +#include "qtest_messagecore.h" + +#include + +#include +#include +#include + +#include +using namespace KPIM; + +QTEST_KDEMAIN( AttachmentCompressJobTest, NoGUI ) + +void AttachmentCompressJobTest::testCompress() +{ + // Some data. + QByteArray data; + for( int i = 0; i < 100; i++ ) { + data += "This is some highly compressible text...\n"; + } + const QString name = QString::fromLatin1( "name" ); + const QString fileName = QString::fromLatin1( "name.txt" ); + const QString description = QString::fromLatin1( "description" ); + + // Create the original part. + AttachmentPart::Ptr origPart = AttachmentPart::Ptr( new AttachmentPart ); + origPart->setName( name ); + origPart->setFileName( fileName ); + origPart->setDescription( description ); + origPart->setMimeType( "text/plain" ); + origPart->setEncoding( KMime::Headers::CE7Bit ); + QVERIFY( !origPart->isAutoEncoding() ); + origPart->setData( data ); + QVERIFY( !origPart->isCompressed() ); + + // Compress the part and verify it. + AttachmentCompressJob *cjob = new AttachmentCompressJob( origPart, this ); + VERIFYEXEC( cjob ); + QCOMPARE( cjob->originalPart(), origPart ); + AttachmentPart::Ptr zipPart = cjob->compressedPart(); + //kDebug() << data; + //kDebug() << zipPart->data(); + QVERIFY( zipPart->isAutoEncoding() ); + QVERIFY( zipPart->isCompressed() ); + QCOMPARE( zipPart->name(), name + QString::fromLatin1( ".zip" ) ); + QCOMPARE( zipPart->fileName(), fileName + QString::fromLatin1( ".zip" ) ); + QCOMPARE( zipPart->description(), description ); + QCOMPARE( zipPart->mimeType(), QByteArray( "application/zip" ) ); + + // Uncompress the data and verify it. + // (Stuff below is stolen from KMail code.) + QByteArray zipData = zipPart->data(); + QBuffer buffer( &zipData ); + KZip zip( &buffer ); + QVERIFY( zip.open( QIODevice::ReadOnly ) ); + const KArchiveDirectory *dir = zip.directory(); + QCOMPARE( dir->entries().count(), 1 ); + const KZipFileEntry *entry = (KZipFileEntry*)dir->entry( dir->entries()[0] ); + QCOMPARE( entry->data(), data ); + QCOMPARE( entry->name(), name ); + zip.close(); +} + +void AttachmentCompressJobTest::testCompressedSizeLarger() +{ + // Some data. + QByteArray data( "This is short enough that compressing it is not efficient." ); + const QString name = QString::fromLatin1( "name.txt" ); + const QString description = QString::fromLatin1( "description" ); + + // Create the original part. + AttachmentPart::Ptr origPart = AttachmentPart::Ptr( new AttachmentPart ); + origPart->setName( name ); + origPart->setDescription( description ); + origPart->setMimeType( "text/plain" ); + origPart->setEncoding( KMime::Headers::CE7Bit ); + QVERIFY( !origPart->isAutoEncoding() ); + origPart->setData( data ); + QVERIFY( !origPart->isCompressed() ); + + // Compress the part and verify that it is aware of its folly. + AttachmentCompressJob *cjob = new AttachmentCompressJob( origPart, this ); + VERIFYEXEC( cjob ); + QVERIFY( cjob->isCompressedPartLarger() ); +} + +#include "attachmentcompressjobtest.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentcompressjobtest.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentcompressjobtest.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentcompressjobtest.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentcompressjobtest.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,33 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef ATTACHMENTCOMPRESSJOBTEST_H +#define ATTACHMENTCOMPRESSJOBTEST_H + +#include + +class AttachmentCompressJobTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testCompress(); + void testCompressedSizeLarger(); +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentfrommimecontentjobtest.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentfrommimecontentjobtest.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentfrommimecontentjobtest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentfrommimecontentjobtest.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,80 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentfrommimecontentjobtest.h" +#include "qtest_messagecore.h" + +#include + +#include +#include + +#include +#include +using namespace KMime; + +#include +using namespace KPIM; + +QTEST_KDEMAIN( AttachmentFromMimeContentJobTest, NoGUI ) + +void AttachmentFromMimeContentJobTest::testAttachment() +{ + const QByteArray mimeType( "x-some/x-type" ); + const QString name = QString::fromLatin1( "name abcd" ); + const QString description = QString::fromLatin1( "description" ); + const QByteArray charset( "utf-8" ); + const QString fileName = QString::fromLatin1( "filename abcd" ); + const Headers::contentEncoding encoding = Headers::CEquPr; + const Headers::contentDisposition disposition = Headers::CDinline; + const QByteArray data( "ocean soul" ); + + Content *content = new Content; + content->contentType()->setMimeType( mimeType ); + content->contentType()->setName( name, charset ); + content->contentType()->setCharset( charset ); + content->contentTransferEncoding()->setEncoding( encoding ); + content->contentDisposition()->setDisposition( disposition ); + content->contentDisposition()->setFilename( fileName ); + content->contentDescription()->fromUnicodeString( description, charset ); + content->setBody( data ); + content->assemble(); + //kDebug() << "Encoded content:" << content->encodedContent(); + //kDebug() << "Decoded content:" << content->decodedContent(); + + AttachmentFromMimeContentJob *job = new AttachmentFromMimeContentJob( content, this ); + QVERIFY( job->uiDelegate() == 0 ); // No GUI thankyouverymuch. + VERIFYEXEC( job ); + delete content; + content = 0; + AttachmentPart::Ptr part = job->attachmentPart(); + delete job; + job = 0; + + QCOMPARE( part->mimeType(), mimeType ); + QCOMPARE( part->name(), name ); + QCOMPARE( part->description(), description ); + //QCOMPARE( part->charset(), charset ); // TODO will probably need charsets in AttachmentPart :( + QCOMPARE( part->fileName(), fileName ); + QVERIFY( part->encoding() == encoding ); + QVERIFY( part->isInline() ); + QCOMPARE( part->data(), data ); +} + +#include "attachmentfrommimecontentjobtest.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentfrommimecontentjobtest.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentfrommimecontentjobtest.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentfrommimecontentjobtest.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentfrommimecontentjobtest.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,33 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef ATTACHMENTFROMMIMECONTENTJOBTEST_H +#define ATTACHMENTFROMMIMECONTENTJOBTEST_H + +#include + +// 33-byte class names say I suck? +class AttachmentFromMimeContentJobTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testAttachment(); +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentfromurljobtest.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentfromurljobtest.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentfromurljobtest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentfromurljobtest.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,103 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentfromurljobtest.h" +#include "qtest_messagecore.h" + +#include + +#include + +#include +using namespace KPIM; + +QTEST_KDEMAIN( AttachmentFromUrlJobTest, NoGUI ) + +void AttachmentFromUrlJobTest::testAttachments_data() +{ + QTest::addColumn( "url" ); + QTest::addColumn( "filename" ); + QTest::addColumn( "mimetype" ); + + // PATH_ATTACHMENTS is defined by CMake. + QTest::newRow( "png image" ) << KUrl::fromPath( PATH_ATTACHMENTS + QString::fromLatin1( "image.png" ) ) + << QString::fromLatin1( "image.png" ) + << QByteArray( "image/png" ); + QTest::newRow( "pdf doc" ) << KUrl::fromPath( PATH_ATTACHMENTS + QString::fromLatin1( "doc.pdf" ) ) + << QString::fromLatin1( "doc.pdf" ) + << QByteArray( "application/pdf" ); + QTest::newRow( "text file" ) << KUrl::fromPath( PATH_ATTACHMENTS + QString::fromLatin1( "file.txt" ) ) + << QString::fromLatin1( "file.txt" ) + << QByteArray( "text/plain" ); +} + +void AttachmentFromUrlJobTest::testAttachments() +{ + QFETCH( KUrl, url ); + QFETCH( QString, filename ); + QFETCH( QByteArray, mimetype ); + + QFile file( url.path() ); + QVERIFY( file.open(QIODevice::ReadOnly) ); + QByteArray data = file.readAll(); + file.close(); + + AttachmentFromUrlJob *ljob = new AttachmentFromUrlJob( url, this ); + VERIFYEXEC( ljob ); + AttachmentPart::Ptr part = ljob->attachmentPart(); + delete ljob; + ljob = 0; + + QCOMPARE( part->name(), filename ); + QCOMPARE( part->fileName(), filename ); + QVERIFY( !part->isInline() ); + QCOMPARE( part->mimeType(), mimetype ); + QCOMPARE( part->data(), data ); +} + +void AttachmentFromUrlJobTest::testAttachmentTooBig() +{ + const KUrl url = KUrl::fromPath( PATH_ATTACHMENTS + QString::fromLatin1( "doc.pdf" ) ); + const QString name = QString::fromLatin1( "doc.pdf" ); + const QByteArray mimetype( "application/pdf" ); + + AttachmentFromUrlJob *ljob = new AttachmentFromUrlJob( url, this ); + ljob->setMaximumAllowedSize( 1024 ); // 1KiB, whereas the file is >9KiB. + QVERIFY( !ljob->exec() ); +} + +void AttachmentFromUrlJobTest::testAttachmentCharset() +{ + const QByteArray charset( "iso-8859-2" ); + const QString filename = QString::fromLatin1( "file.txt" ); + KUrl url = KUrl::fromPath( PATH_ATTACHMENTS + filename ); + url.setFileEncoding( charset ); + + AttachmentFromUrlJob *ljob = new AttachmentFromUrlJob( url, this ); + VERIFYEXEC( ljob ); + AttachmentPart::Ptr part = ljob->attachmentPart(); + delete ljob; + ljob = 0; + + QCOMPARE( part->name(), filename ); + QCOMPARE( part->fileName(), filename ); + QCOMPARE( part->charset(), charset ); +} + +#include "attachmentfromurljobtest.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentfromurljobtest.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentfromurljobtest.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentfromurljobtest.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentfromurljobtest.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,35 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef ATTACHMENTFROMURLJOBTEST_H +#define ATTACHMENTFROMURLJOBTEST_H + +#include + +class AttachmentFromUrlJobTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testAttachments_data(); + void testAttachments(); + void testAttachmentTooBig(); + void testAttachmentCharset(); +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentparttest.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentparttest.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentparttest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentparttest.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,51 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentparttest.h" +#include "qtest_messagecore.h" + +#include + +#include +#include + +#include +#include +using namespace KPIM; + +QTEST_KDEMAIN( AttachmentPartTest, NoGUI ) + +void AttachmentPartTest::testApi() +{ + const QString str = QString::fromLatin1( "test" ); + AttachmentPart::Ptr part = AttachmentPart::Ptr( new AttachmentPart ); + + // Test that an AttachmentPart::Ptr can be put in a QHash. + QHash hash; + hash[ part ] = str; + QVERIFY( hash.contains( part ) ); + + // Test that an AttachmentPart::Ptr can be put in a QVariant. + QVariant variant = QVariant::fromValue( part ); + QVERIFY( variant.isValid() ); + QVERIFY( variant.canConvert() ); + QVERIFY( variant.value() == part ); +} + +#include "attachmentparttest.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentparttest.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentparttest.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentparttest.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentparttest.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,32 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef ATTACHMENTPARTTEST_H +#define ATTACHMENTPARTTEST_H + +#include + +class AttachmentPartTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testApi(); +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentpropertiesdialogtest.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentpropertiesdialogtest.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentpropertiesdialogtest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentpropertiesdialogtest.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,189 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentpropertiesdialogtest.h" +#include "qtest_messagecore.h" + +#include + +#include + +#include +#include +#include +#include + +#include +using namespace KMime; + +#include +#include +using namespace KPIM; + +QTEST_KDEMAIN( AttachmentPropertiesDialogTest, GUI ) + +void AttachmentPropertiesDialogTest::testAttachmentPartReadWrite() +{ + // Sample data. + const QString name = QString::fromLatin1( "old name" ); + const QString newName = QString::fromLatin1( "new name" ); + const QString description = QString::fromLatin1( "old description" ); + const QString newDescription = QString::fromLatin1( "new description" ); + const QByteArray data( "12345" ); + const QByteArray mimeType( "text/plain" ); + const QByteArray newMimeType( "x-weird/x-type" ); + const Headers::contentEncoding encoding = Headers::CEquPr; + const Headers::contentEncoding newEncoding = Headers::CE7Bit; + const bool autoDisplay = true; + const bool encrypt = true; + const bool sign = true; + + // Create the part. + AttachmentPart::Ptr part = AttachmentPart::Ptr( new AttachmentPart ); + part->setName( name ); + part->setDescription( description ); + part->setData( data ); + part->setMimeType( mimeType ); + part->setEncoding( encoding ); + part->setInline( autoDisplay ); + part->setEncrypted( encrypt ); + part->setSigned( sign ); + + // Show the dialog and verify that it is accurate. + AttachmentPropertiesDialog *dialog = new AttachmentPropertiesDialog( part ); + dialog->show(); + KLineEdit *nameEdit = dialog->findChild( QLatin1String( "name" ) ); + Q_ASSERT( nameEdit ); + QCOMPARE( nameEdit->text(), name ); + KLineEdit *descriptionEdit = dialog->findChild( QLatin1String( "description" ) ); + Q_ASSERT( descriptionEdit ); + QCOMPARE( descriptionEdit->text(), description ); + KComboBox *mimeTypeCombo = dialog->findChild( QLatin1String( "mimeType" ) ); + Q_ASSERT( mimeTypeCombo ); + QCOMPARE( mimeTypeCombo->currentText().toLatin1(), mimeType ); + KComboBox *encodingCombo = dialog->findChild( QLatin1String( "encoding" ) ); + Q_ASSERT( encodingCombo ); + QCOMPARE( encodingCombo->currentIndex(), int( encoding ) ); + QCheckBox *autoDisplayCheck = dialog->findChild( QLatin1String( "autoDisplay" ) ); + Q_ASSERT( autoDisplayCheck ); + QCOMPARE( autoDisplayCheck->isChecked(), autoDisplay ); + QCheckBox *encryptCheck = dialog->findChild( QLatin1String( "encrypt" ) ); + Q_ASSERT( encryptCheck ); + QCOMPARE( encryptCheck->isChecked(), encrypt ); + QCheckBox *signCheck = dialog->findChild( QLatin1String( "sign" ) ); + Q_ASSERT( signCheck ); + QCOMPARE( signCheck->isChecked(), sign ); + //QTest::qWait( 5000 ); + + // Make some changes in the dialog. + nameEdit->setText( newName ); + descriptionEdit->setText( newDescription ); + mimeTypeCombo->setCurrentItem( newMimeType, true ); + encodingCombo->setCurrentIndex( int( newEncoding ) ); + autoDisplayCheck->setChecked( !autoDisplay ); + encryptCheck->setChecked( !encrypt ); + signCheck->setChecked( !sign ); + + // Click on 'OK' and verify changes. + dialog->accept(); + delete dialog; + QCOMPARE( part->name(), newName ); + QCOMPARE( part->description(), newDescription ); + QCOMPARE( part->data(), data ); // Unchanged. + QCOMPARE( part->mimeType(), newMimeType ); + QCOMPARE( int( part->encoding() ), int( newEncoding ) ); + QCOMPARE( part->isInline(), !autoDisplay ); + QCOMPARE( part->isEncrypted(), !encrypt ); + QCOMPARE( part->isSigned(), !sign ); +} + +void AttachmentPropertiesDialogTest::testAttachmentPartReadOnly() +{ + // Sample data. + const QString name = QString::fromLatin1( "old name" ); + const QString newName = QString::fromLatin1( "new name" ); + + // Create the part. + AttachmentPart::Ptr part = AttachmentPart::Ptr( new AttachmentPart ); + part->setName( name ); + + // Show the (read-only) dialog and do some changes. + AttachmentPropertiesDialog *dialog = new AttachmentPropertiesDialog( part, 0, true ); + dialog->show(); + KLineEdit *nameEdit = dialog->findChild( QLatin1String( "name" ) ); + Q_ASSERT( nameEdit ); + nameEdit->setText( newName ); + + // Click on 'OK'. No changes should have been made. + dialog->accept(); + delete dialog; + QCOMPARE( part->name(), name ); // No change. +} + +void AttachmentPropertiesDialogTest::testAttachmentPartCancel() +{ + // Sample data. + const QString name = QString::fromLatin1( "old name" ); + const QString newName = QString::fromLatin1( "new name" ); + + // Create the part. + AttachmentPart::Ptr part = AttachmentPart::Ptr( new AttachmentPart ); + part->setName( name ); + + // Show the (read-write) dialog and do some changes. + AttachmentPropertiesDialog *dialog = new AttachmentPropertiesDialog( part ); + dialog->show(); + KLineEdit *nameEdit = dialog->findChild( QLatin1String( "name" ) ); + Q_ASSERT( nameEdit ); + nameEdit->setText( newName ); + + // Click on 'Cancel'. No changes should have been made. + dialog->reject(); + delete dialog; + QCOMPARE( part->name(), name ); // No change. +} + +void AttachmentPropertiesDialogTest::testMimeContentReadOnly() +{ + // Sample data. + const QString name = QString::fromLatin1( "old name" ); + const QString newName = QString::fromLatin1( "new name" ); + const QByteArray charset( "us-ascii" ); + + // Create the MIME Content. + Content *content = new Content; + content->contentType()->setName( name, charset ); + const Content *constContent = content; + + // Show the (read-only) dialog and do some changes. + AttachmentPropertiesDialog *dialog = new AttachmentPropertiesDialog( constContent ); + dialog->show(); + KLineEdit *nameEdit = dialog->findChild( QLatin1String( "name" ) ); + QVERIFY( nameEdit->isReadOnly() ); + QCOMPARE( nameEdit->text(), name ); + Q_ASSERT( nameEdit ); + nameEdit->setText( newName ); + + // Click on 'OK'. The MIME Content should be untouched. + dialog->accept(); + delete dialog; + QCOMPARE( content->contentType()->name(), name ); // No change. +} + +#include "attachmentpropertiesdialogtest.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentpropertiesdialogtest.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentpropertiesdialogtest.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachmentpropertiesdialogtest.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachmentpropertiesdialogtest.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,35 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef ATTACHMENTPROPERTIESDIALOGTEST_H +#define ATTACHMENTPROPERTIESDIALOGTEST_H + +#include + +class AttachmentPropertiesDialogTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testAttachmentPartReadWrite(); + void testAttachmentPartReadOnly(); + void testAttachmentPartCancel(); + void testMimeContentReadOnly(); +}; + +#endif Binary files /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachments/doc.pdf and /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachments/doc.pdf differ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachments/file.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachments/file.txt --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachments/file.txt 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachments/file.txt 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,2 @@ +some plain ascii text... + Binary files /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/attachments/image.png and /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/attachments/image.png differ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/CMakeLists.txt 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,22 @@ +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) + +include_directories( ${Boost_INCLUDE_DIR} ) + +# Location of the attachments to test. +set( attachments_root "QLatin1String( \"${CMAKE_CURRENT_SOURCE_DIR}/attachments/\" )" ) +add_definitions( -DPATH_ATTACHMENTS='${attachments_root}' ) + +# Convenience macro to add unit tests. +macro( add_messagecore_test _source ) + set( _test ${_source} ) + get_filename_component( _name ${_source} NAME_WE ) + kde4_add_unit_test( ${_name} TESTNAME messagecore-${_name} ${_test} ) + target_link_libraries( ${_name} messagecore ${QT_QTTEST_LIBRARY} ${KDE4_KDEUI_LIBS} ) +endmacro( add_messagecore_test ) + +# Attachment tests. +add_messagecore_test( attachmentcompressjobtest.cpp ) +add_messagecore_test( attachmentfrommimecontentjobtest.cpp ) +add_messagecore_test( attachmentfromurljobtest.cpp ) +add_messagecore_test( attachmentparttest.cpp ) +add_messagecore_test( attachmentpropertiesdialogtest.cpp ) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/qtest_messagecore.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/qtest_messagecore.h --- kde-nightly-kdepim-20091006+svn1032120/messagecore/tests/qtest_messagecore.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagecore/tests/qtest_messagecore.h 2009-10-09 23:30:58.000000000 +0100 @@ -0,0 +1,34 @@ +/* + Copyright (C) 2009 Constantin Berzan + + Based on Akonadi code by: + Copyright (C) 2009 Volker Krause + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef QTEST_LIBKDEPIM_H +#define QTEST_LIBKDEPIM_H + +/** + * Runs a KJob synchronously and aborts if the job failed. + * Similar to QVERIFY( job->exec() ) but includes the job error message + * in the output in case of a failure. + */ +// TODO move to qtest_kde... +#define VERIFYEXEC( job ) \ + QVERIFY2( job->exec(), job->errorString().toUtf8().constData() ) + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/messagelist/CMakeLists.txt 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/CMakeLists.txt 2009-10-09 23:30:58.000000000 +0100 @@ -84,7 +84,7 @@ ${KDEPIMLIBS_AKONADI_LIBS} ${KDEPIMLIBS_AKONADI_KMIME_LIBS} ${KDEPIMLIBS_KMIME_LIBS} - kdepim + messagecore ) set_target_properties(messagelist PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/core/item.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/core/item.h --- kde-nightly-kdepim-20091006+svn1032120/messagelist/core/item.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/core/item.h 2009-10-09 23:30:58.000000000 +0100 @@ -29,7 +29,7 @@ #include -#include +#include #include #include diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/core/model.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/core/model.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagelist/core/model.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/core/model.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -53,8 +53,7 @@ #include "core/manager.h" #include "core/messageitemsetmanager.h" -#include // KPIM::BroadcastStatus -#include +#include #include #include @@ -3844,19 +3843,34 @@ case ViewItemJob::Pass1Fill: case ViewItemJob::Pass1Cleanup: case ViewItemJob::Pass1Update: - KPIM::BroadcastStatus::instance()->setStatusMsg( i18np("Processed 1 Message of %2", "Processed %1 Messages of %2", job->currentIndex() - job->startIndex(), ( job->endIndex() - job->startIndex() ) + 1 ) ); + emit q->statusMessage( i18np( "Processed 1 Message of %2", + "Processed %1 Messages of %2", + job->currentIndex() - job->startIndex(), + job->endIndex() - job->startIndex() + 1 ) ); break; case ViewItemJob::Pass2: - KPIM::BroadcastStatus::instance()->setStatusMsg( i18np("Threaded 1 Message of %2", "Threaded %1 Messages of %2", job->currentIndex() - job->startIndex(), ( job->endIndex() - job->startIndex() ) + 1 ) ); + emit q->statusMessage( i18np( "Threaded 1 Message of %2", + "Threaded %1 Messages of %2", + job->currentIndex() - job->startIndex(), + job->endIndex() - job->startIndex() + 1 ) ); break; case ViewItemJob::Pass3: - KPIM::BroadcastStatus::instance()->setStatusMsg( i18np("Threaded 1 Message of %2", "Threaded %1 Messages of %2", job->currentIndex() - job->startIndex(), ( job->endIndex() - job->startIndex() ) + 1 ) ); + emit q->statusMessage( i18np( "Threaded 1 Message of %2", + "Threaded %1 Messages of %2", + job->currentIndex() - job->startIndex(), + job->endIndex() - job->startIndex() + 1 ) ); break; case ViewItemJob::Pass4: - KPIM::BroadcastStatus::instance()->setStatusMsg( i18np("Grouped 1 Thread of %2", "Grouped %1 Threads of %2", job->currentIndex() - job->startIndex(), ( job->endIndex() - job->startIndex() ) + 1 ) ); + emit q->statusMessage( i18np( "Grouped 1 Thread of %2", + "Grouped %1 Threads of %2", + job->currentIndex() - job->startIndex(), + job->endIndex() - job->startIndex() + 1 ) ); break; case ViewItemJob::Pass5: - KPIM::BroadcastStatus::instance()->setStatusMsg( i18np("Updated 1 Group of %2", "Updated %1 Groups of %2", job->currentIndex() - job->startIndex(), ( job->endIndex() - job->startIndex() ) + 1 ) ); + emit q->statusMessage( i18np( "Updated 1 Group of %2", + "Updated %1 Groups of %2", + job->currentIndex() - job->startIndex(), + job->endIndex() - job->startIndex() + 1 ) ); break; default: break; } @@ -3949,7 +3963,7 @@ // no more jobs - KPIM::BroadcastStatus::instance()->setStatusMsg( i18nc( "@info:status Finished view fill", "Ready" ) ); + emit q->statusMessage( i18nc( "@info:status Finished view fill", "Ready" ) ); return ViewItemJobCompleted; } diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/core/model.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/core/model.h --- kde-nightly-kdepim-20091006+svn1032120/messagelist/core/model.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/core/model.h 2009-10-09 23:30:58.000000000 +0100 @@ -238,6 +238,13 @@ virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const; virtual Qt::ItemFlags flags( const QModelIndex &index ) const; +Q_SIGNALS: + /** + * Notify the outside when updating the status bar with a message + * could be useful + */ + void statusMessage( const QString &message ); + private: Q_PRIVATE_SLOT(d, void checkIfDateChanged()) Q_PRIVATE_SLOT(d, void viewItemJobStep()) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/core/subjectutils.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/core/subjectutils.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagelist/core/subjectutils.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/core/subjectutils.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -20,17 +20,30 @@ #include "subjectutils_p.h" +#include #include #include #include +#include "configprovider.h" + QString MessageList::Core::SubjectUtils::stripOffPrefixes( const QString &subject ) { + KConfigGroup composerGroup( ConfigProvider::self()->config(), "Composer" ); + + QStringList replyPrefixes = composerGroup.readEntry( "reply-prefixes", QStringList() ); + if ( replyPrefixes.isEmpty() ) { + replyPrefixes << "Re\\s*:" << "Re\\[\\d+\\]:" << "Re\\d+:"; + } + + QStringList forwardPrefixes = composerGroup.readEntry( "forward-prefixes", QStringList() ); + if ( forwardPrefixes.isEmpty() ) { + forwardPrefixes << "Fwd:" << "FW:"; + } + QString str = subject; - QStringList prefixRegExps; - prefixRegExps << "Re\\s*:" << "Re\\[\\d+\\]:" << "Re\\d+:" - << "Fwd:" << "FW:"; + const QStringList prefixRegExps = replyPrefixes + forwardPrefixes; // construct a big regexp that // 1. is anchored to the beginning of str (sans whitespace) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/core/view.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/core/view.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagelist/core/view.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/core/view.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -33,7 +33,6 @@ #include "core/widgetbase.h" #include // kdepimlibs -#include #include #include @@ -114,6 +113,9 @@ d->mModel = new Model( this ); setModel( d->mModel ); + connect( d->mModel, SIGNAL( statusMessage( const QString & ) ), + pParent, SIGNAL( statusMessage( const QString & ) ) ); + //connect( selectionModel(), SIGNAL( currentChanged( const QModelIndex &, const QModelIndex & ) ), // this, SLOT( slotCurrentIndexChanged( const QModelIndex &, const QModelIndex & ) ) ); connect( selectionModel(), SIGNAL( selectionChanged( const QItemSelection &, const QItemSelection & ) ), @@ -2594,4 +2596,9 @@ setAllGroupsExpanded( true ); } +void View::focusQuickSearch() +{ + d->mWidget->focusQuickSearch(); +} + #include "view.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/core/view.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/core/view.h --- kde-nightly-kdepim-20091006+svn1032120/messagelist/core/view.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/core/view.h 2009-10-09 23:30:58.000000000 +0100 @@ -342,6 +342,10 @@ */ void fillViewMenu( KMenu * menu ); + /** + * Sets the focus on the quick search line of the currently active tab. + */ + void focusQuickSearch(); protected: /** * Reimplemented in order to catch QHelpEvent diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/core/widgetbase.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/core/widgetbase.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagelist/core/widgetbase.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/core/widgetbase.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -50,7 +50,7 @@ #include #include -#include +#include using namespace MessageList::Core; @@ -1108,3 +1108,11 @@ Q_UNUSED( clear ); } +void Widget::focusQuickSearch() +{ + if ( d->mSearchEdit ) + { + d->mSearchEdit->setFocus(); + } +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/core/widgetbase.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/core/widgetbase.h --- kde-nightly-kdepim-20091006+svn1032120/messagelist/core/widgetbase.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/core/widgetbase.h 2009-10-09 23:30:58.000000000 +0100 @@ -109,6 +109,12 @@ */ QString currentFilterTagId() const; + /** + * Sets the focus on the quick search line of the currently active tab. + */ + void focusQuickSearch(); + + public slots: /** @@ -190,12 +196,18 @@ void tagIdSelected( QVariant data ); -signals: +Q_SIGNALS: /** * Emitted when a full search is requested. */ void fullSearchRequest(); + /** + * Notify the outside when updating the status bar with a message + * could be useful + */ + void statusMessage( const QString &message ); + protected slots: /** * This is called by Manager when the option sets stored within have changed. diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/pane.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/pane.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagelist/pane.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/pane.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -39,7 +39,7 @@ { public: Private( Pane *owner ) - : q( owner ) { } + : q( owner ), mXmlGuiClient( 0 ) { } void onSelectionChanged( const QItemSelection &selected, const QItemSelection &deselected ); void onNewTabClicked(); @@ -53,6 +53,8 @@ Pane * const q; + KXMLGUIClient *mXmlGuiClient; + QAbstractItemModel *mModel; QItemSelectionModel *mSelectionModel; @@ -66,6 +68,7 @@ } // namespace MessageList +using namespace Akonadi; using namespace MessageList; @@ -131,6 +134,16 @@ delete d; } +void Pane::setXmlGuiClient( KXMLGUIClient *xmlGuiClient ) +{ + d->mXmlGuiClient = xmlGuiClient; + + for ( int i=0; i( widget( i ) ); + w->setXmlGuiClient( d->mXmlGuiClient ); + } +} + bool Pane::selectNextMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour, bool centerItem, @@ -210,6 +223,43 @@ } } + +void Pane::setCurrentThreadExpanded( bool expand ) +{ + Widget *w = static_cast( currentWidget() ); + + if ( w ) { + w->setCurrentThreadExpanded(expand ); + } +} + +void Pane::setAllThreadsExpanded( bool expand ) +{ + Widget *w = static_cast( currentWidget() ); + + if ( w ) { + w->setAllThreadsExpanded( expand ); + } +} + +void Pane::setAllGroupsExpanded( bool expand ) +{ + Widget *w = static_cast( currentWidget() ); + + if ( w ) { + w->setAllGroupsExpanded(expand); + } +} + +void Pane::focusQuickSearch() +{ + Widget *w = static_cast( currentWidget() ); + + if ( w ) { + w->focusQuickSearch(); + } +} + void Pane::Private::onSelectionChanged( const QItemSelection &selected, const QItemSelection &deselected ) { Widget *w = static_cast( q->currentWidget() ); @@ -315,6 +365,7 @@ void Pane::createNewTab() { Widget * w = new Widget( this ); + w->setXmlGuiClient( d->mXmlGuiClient ); addTab( w, i18nc( "@title:tab Empty messagelist", "Empty" ) ); QItemSelectionModel *s = new QItemSelectionModel( d->mModel, w ); @@ -332,6 +383,10 @@ connect( w, SIGNAL(messageStatusChangeRequest(Akonadi::Item, KPIM::MessageStatus, KPIM::MessageStatus)), this, SIGNAL(messageStatusChangeRequest(Akonadi::Item, KPIM::MessageStatus, KPIM::MessageStatus)) ); + connect( w, SIGNAL(statusMessage(QString)), + this, SIGNAL(statusMessage(QString)) ); + + connect( w, SIGNAL( fullSearchRequest() ), this, SIGNAL( fullSearchRequest() ) ); d->updateTabControls(); setCurrentWidget( w ); } @@ -372,4 +427,26 @@ } } +Item Pane::currentItem() const +{ + Widget *w = static_cast( currentWidget() ); + + if ( w == 0 ) { + return Item(); + } + + return w->currentItem(); +} + +MessagePtr Pane::currentMessage() const +{ + Widget *w = static_cast( currentWidget() ); + + if ( w == 0 ) { + return MessagePtr(); + } + + return w->currentMessage(); +} + #include "pane.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/pane.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/pane.h --- kde-nightly-kdepim-20091006+svn1032120/messagelist/pane.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/pane.h 2009-10-09 23:30:58.000000000 +0100 @@ -24,13 +24,19 @@ #include #include +#include +#include + +#include + +class KXMLGUIClient; class QAbstractItemModel; class QAbstractProxyModel; class QItemSelectionModel; class QItemSelection; class QToolButton; -#include +typedef boost::shared_ptr MessagePtr; namespace KPIM { @@ -51,6 +57,11 @@ * This is the main MessageList panel for Akonadi applications. * It contains multiple MessageList::Widget tabs * so it can actually display multiple folder sets at once. + * + * When a KXmlGuiWindow is passed to setXmlGuiClient, the XMLGUI + * defined context menu @c akonadi_messagelist_contextmenu is + * used if available. + * */ class MESSAGELIST_EXPORT Pane : public QTabWidget { @@ -64,6 +75,29 @@ ~Pane(); /** + * Sets the XML GUI client which the pane is used in. + * + * This is needed if you want to use the built-in context menu. + * Passing 0 is ok and will disable the builtin context menu. + * + * @param xmlGuiClient The KXMLGUIClient the view is used in. + */ + void setXmlGuiClient( KXMLGUIClient *xmlGuiClient ); + + /** + * Returns the current message for the list as Akonadi::Item. + * May return an invalid Item if there is no current message or no current folder. + */ + Akonadi::Item currentItem() const; + + /** + * Returns the current message for the list as MessagePtr. + * May return 0 if there is no current message or no current folder. + */ + MessagePtr currentMessage() const; + + + /** * Selects the next message item in the view. * * messageTypeFilter can be used to restrict the selection to only certain message types. @@ -148,6 +182,32 @@ */ bool selectFirstMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem ); + + /** + * If expand is true then it expands the current thread, otherwise + * collapses it. + */ + void setCurrentThreadExpanded( bool expand ); + + /** + * If expand is true then it expands all the threads, otherwise + * collapses them. + */ + void setAllThreadsExpanded( bool expand ); + + /** + * If expand is true then it expands all the groups (only the toplevel + * group item: inner threads are NOT expanded). If expand is false + * then it collapses all the groups. If no grouping is in effect + * then this function does nothing. + */ + void setAllGroupsExpanded( bool expand ); + + /** + * Sets the focus on the quick search line of the currently active tab. + */ + void focusQuickSearch(); + public slots: /** * Selects all the items in the current folder. @@ -187,6 +247,17 @@ */ void messageStatusChangeRequest( const Akonadi::Item &item, const KPIM::MessageStatus &set, const KPIM::MessageStatus &clear ); + /** + * Emitted when a full search is requested. + */ + void fullSearchRequest(); + + /** + * Notify the outside when updating the status bar with a message + * could be useful + */ + void statusMessage( const QString &message ); + private: Q_PRIVATE_SLOT(d, void onSelectionChanged( const QItemSelection&, const QItemSelection& )) Q_PRIVATE_SLOT(d, void onNewTabClicked()) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/utils/themeeditor.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/utils/themeeditor.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagelist/utils/themeeditor.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/utils/themeeditor.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -26,7 +26,7 @@ #include "core/manager.h" #include "utils/comboboxutils.h" -#include +#include #include #include diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/widget.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/widget.cpp --- kde-nightly-kdepim-20091006+svn1032120/messagelist/widget.cpp 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/widget.cpp 2009-10-09 23:30:58.000000000 +0100 @@ -40,6 +40,8 @@ #include #include #include +#include +#include namespace MessageList { @@ -48,14 +50,16 @@ { public: Private( Widget *owner ) - : q( owner ) { } + : q( owner ), mXmlGuiClient( 0 ) { } Akonadi::Item::List selectionAsItems() const; Akonadi::Item itemForRow( int row ) const; + MessagePtr messageForRow( int row ) const; Widget * const q; int mLastSelectedMessage; + KXMLGUIClient *mXmlGuiClient; }; } // namespace MessageList @@ -63,70 +67,44 @@ using namespace MessageList; using namespace Akonadi; -struct DragPayload -{ - QList sourceCollections; - QList items; - bool readOnly; - - DragPayload() : readOnly( false ) { } - - static QString mimeType() - { - return "x-akonadi-drag/message-list"; - } -}; - -QDataStream &operator<<(QDataStream &stream, const DragPayload &payload) -{ - stream << payload.sourceCollections; - stream << payload.items; - stream << payload.readOnly; - - return stream; -} - -QDataStream &operator>>(QDataStream &stream, DragPayload &payload) -{ - stream >> payload.sourceCollections; - stream >> payload.items; - stream >> payload.readOnly; - - return stream; -} - Widget::Widget( QWidget *parent ) : Core::Widget( parent ), d( new Private( this ) ) { - QTimer::singleShot( 0, this, SLOT( populateStatusFilterCombo() ) ); + populateStatusFilterCombo(); } Widget::~Widget() { + delete d; } -bool Widget::canAcceptDrag( const QDragMoveEvent * e ) +void Widget::setXmlGuiClient( KXMLGUIClient *xmlGuiClient ) +{ + d->mXmlGuiClient = xmlGuiClient; +} + +bool Widget::canAcceptDrag( const QDropEvent * e ) { Collection::List collections = static_cast( storageModel() )->displayedCollections(); if ( collections.size()!=1 ) return false; // no folder here or too many (in case we can't decide where the drop will end) - Collection c = collections.first(); + const Collection target = collections.first(); - if ( ( c.rights() & Collection::CanCreateItem ) == 0 ) + if ( ( target.rights() & Collection::CanCreateItem ) == 0 ) return false; // no way to drag into - if ( !e->mimeData()->hasFormat( DragPayload::mimeType() ) ) - return false; // no way to decode it - - DragPayload payload; - QDataStream stream( e->mimeData()->data( DragPayload::mimeType() ) ); - stream >> payload; - - foreach ( Collection::Id id, payload.sourceCollections ) { - if ( id == c.id() ) { + const KUrl::List urls = KUrl::List::fromMimeData( e->mimeData() ); + foreach ( const KUrl &url, urls ) { + const Collection collection = Collection::fromUrl( url ); + if ( collection.isValid() ) { // You're not supposed to drop collections here return false; + } else { // Yay, this is an item! + const QString type = url.queryItems()["type"]; // But does it have the right type? + if ( !target.contentMimeTypes().contains( type ) ) { + return false; + } } } @@ -175,6 +153,26 @@ view()->selectAll(); } +void Widget::setCurrentThreadExpanded( bool expand ) +{ + view()->setCurrentThreadExpanded(expand ); +} + +void Widget::setAllThreadsExpanded( bool expand ) +{ + view()->setAllThreadsExpanded( expand ); +} + +void Widget::setAllGroupsExpanded( bool expand ) +{ + view()->setAllGroupsExpanded(expand); +} + +void Widget::focusQuickSearch() +{ + view()->focusQuickSearch(); +} + void Widget::viewMessageSelected( MessageList::Core::MessageItem *msg ) { int row = -1; @@ -232,10 +230,18 @@ } } -void Widget::viewMessageListContextPopupRequest( const QList< MessageList::Core::MessageItem * > &selectedItems, const QPoint &globalPos ) +void Widget::viewMessageListContextPopupRequest( const QList< MessageList::Core::MessageItem * > &selectedItems, + const QPoint &globalPos ) { - //FIXME: To implement once the other infrastructure is ready for a KMail independent implementation - kWarning() << "Needs to be reimplemented"; + if ( !d->mXmlGuiClient ) + return; + + QMenu *popup = static_cast( d->mXmlGuiClient->factory()->container( + QLatin1String( "akonadi_messagelist_contextmenu" ), + d->mXmlGuiClient ) ); + if ( popup ) { + popup->exec( globalPos ); + } } void Widget::viewMessageStatusChangeRequest( MessageList::Core::MessageItem *msg, const KPIM::MessageStatus &set, const KPIM::MessageStatus &clear ) @@ -306,19 +312,13 @@ void Widget::viewDropEvent( QDropEvent *e ) { - Collection::List collections = static_cast( storageModel() )->displayedCollections(); - - if ( collections.size()!=1 || !e->mimeData()->hasFormat( DragPayload::mimeType() ) ) { - // no folder here or too many (in case we can't decide where the drop will end), or we can't decode + if ( !canAcceptDrag( e ) ) { e->ignore(); return; } - DragPayload payload; - QDataStream stream( e->mimeData()->data( DragPayload::mimeType() ) ); - stream >> payload; - - if ( payload.items.isEmpty() ) { + KUrl::List urls = KUrl::List::fromMimeData( e->mimeData() ); + if ( urls.isEmpty() ) { kWarning() << "Could not decode drag data!"; e->ignore(); return; @@ -327,7 +327,7 @@ e->accept(); int action; - if ( payload.readOnly ) { + if ( ( e->possibleActions() & Qt::MoveAction ) == 0 ) { // We can't move anyway action = DragCopy; } else { action = DragCancel; @@ -357,10 +357,11 @@ } } + Collection::List collections = static_cast( storageModel() )->displayedCollections(); Collection target = collections.first(); Item::List items; - foreach ( Item::Id id, payload.items ) { - items << Item( id ); + foreach ( const KUrl &url, urls ) { + items << Item::fromUrl( url ); } if ( action == DragCopy ) { @@ -382,29 +383,23 @@ if ( items.isEmpty() ) return; - DragPayload payload; + bool readOnly = false; foreach ( const Collection c, collections ) { - payload.sourceCollections << c.id(); // We won't be able to remove items from this collection if ( ( c.rights() & Collection::CanDeleteItem ) == 0 ) { // So the drag will be read-only - payload.readOnly = true; + readOnly = true; } } + KUrl::List urls; foreach ( const Item i, items ) { - payload.items << i.id(); - } - - QByteArray data; - { - QDataStream stream( &data, QIODevice::WriteOnly ); - stream << payload; + urls << i.url( Item::UrlWithMimeType ); } QMimeData *mimeData = new QMimeData; - mimeData->setData( DragPayload::mimeType(), data ); + urls.populateMimeData( mimeData ); QDrag *drag = new QDrag( view()->viewport() ); drag->setMimeData( mimeData ); @@ -423,7 +418,7 @@ drag->setPixmap( pixmap ); } - if ( payload.readOnly ) + if ( readOnly ) drag->exec( Qt::CopyAction ); else drag->exec( Qt::CopyAction | Qt::MoveAction ); @@ -447,3 +442,30 @@ { return static_cast( q->storageModel() )->itemForRow( row ); } + +MessagePtr Widget::Private::messageForRow( int row ) const +{ + return static_cast( q->storageModel() )->messageForRow( row ); +} + +Item Widget::currentItem() const +{ + Core::MessageItem *mi = view()->currentMessageItem(); + + if ( mi == 0 ) { + return Item(); + } + + return d->itemForRow( mi->currentModelIndexRow() ); +} + +MessagePtr Widget::currentMessage() const +{ + Core::MessageItem *mi = view()->currentMessageItem(); + + if ( mi == 0 ) { + return MessagePtr(); + } + + return d->messageForRow( mi->currentModelIndexRow() ); +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messagelist/widget.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messagelist/widget.h --- kde-nightly-kdepim-20091006+svn1032120/messagelist/widget.h 2009-10-06 23:28:05.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messagelist/widget.h 2009-10-09 23:30:58.000000000 +0100 @@ -23,15 +23,26 @@ #include +#include +#include + #include +class KXMLGUIClient; class QWidget; +typedef boost::shared_ptr MessagePtr; + namespace MessageList { /** * The Akonadi specific implementation of the Core::Widget. + * + * When a KXmlGuiWindow is passed to setXmlGuiClient, the XMLGUI + * defined context menu @c akonadi_messagelist_contextmenu is + * used if available. + * */ class MESSAGELIST_EXPORT Widget : public MessageList::Core::Widget { @@ -39,15 +50,38 @@ public: /** - * Create a Widget wrapping the specified folder. + * Create a new message list widget. */ explicit Widget( QWidget *parent ); ~Widget(); /** + * Sets the XML GUI client which the view is used in. + * + * This is needed if you want to use the built-in context menu. + * Passing 0 is ok and will disable the builtin context menu. + * + * @param xmlGuiClient The KXMLGUIClient the view is used in. + */ + void setXmlGuiClient( KXMLGUIClient *xmlGuiClient ); + + /** + * Returns the current message for the list as Akonadi::Item. + * May return an invalid Item if there is no current message or no current folder. + */ + Akonadi::Item currentItem() const; + + /** + * Returns the current message for the list as MessagePtr. + * May return 0 if there is no current message or no current folder. + */ + MessagePtr currentMessage() const; + + + /** * Returns true if this drag can be accepted by the underlying view */ - bool canAcceptDrag( const QDragMoveEvent *e ); + bool canAcceptDrag( const QDropEvent *e ); /** * Selects the next message item in the view. @@ -138,6 +172,30 @@ * Selects all the items in the current folder. */ void selectAll(); + /** + * If expand is true then it expands the current thread, otherwise + * collapses it. + */ + void setCurrentThreadExpanded( bool expand ); + + /** + * If expand is true then it expands all the threads, otherwise + * collapses them. + */ + void setAllThreadsExpanded( bool expand ); + + /** + * If expand is true then it expands all the groups (only the toplevel + * group item: inner threads are NOT expanded). If expand is false + * then it collapses all the groups. If no grouping is in effect + * then this function does nothing. + */ + void setAllGroupsExpanded( bool expand ); + + /** + * Sets the focus on the quick search line of the currently active tab. + */ + void focusQuickSearch(); protected: /** diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/antispamconfig.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/antispamconfig.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/antispamconfig.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/antispamconfig.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,113 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + antispamconfig.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Patrick Audley + Copyright (c) 2004 Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "antispamconfig.h" + +#include +#include +#include +#include + +#include +namespace MessageViewer { +class AntiSpamConfigSingletonProvider +{ + public: + AntiSpamConfig instance; +}; + +K_GLOBAL_STATIC( AntiSpamConfigSingletonProvider, theAntiSpamConfigSingletonProvider ) + +AntiSpamConfig * AntiSpamConfig::instance() +{ + // better safe than sorry; check whether the global static has already been destroyed + if ( theAntiSpamConfigSingletonProvider.isDestroyed() ) + { + return 0; + } + return &theAntiSpamConfigSingletonProvider->instance; +} + +AntiSpamConfig::AntiSpamConfig() +{ + readConfig(); +} + +void AntiSpamConfig::readConfig() +{ + mAgents.clear(); + KConfig config( "kmail.antispamrc" ); + config.setReadDefaults( true ); + KConfigGroup general( &config, "General" ); + unsigned int totalTools = general.readEntry( "tools", 0 ); + for ( unsigned int i = 1; i <= totalTools; ++i ) { + KConfigGroup tool( &config, QString("Spamtool #%1").arg( i ) ); + if ( tool.hasKey( "ScoreHeader" ) ) { + QString name = tool.readEntry( "ScoreName" ); + QByteArray header = tool.readEntry( "ScoreHeader" ).toLatin1(); + QByteArray cheader = tool.readEntry( "ConfidenceHeader" ).toLatin1(); + QByteArray type = tool.readEntry( "ScoreType" ).toLatin1(); + QString score = tool.readEntryUntranslated( "ScoreValueRegexp" ); + QString threshold = tool.readEntryUntranslated( "ScoreThresholdRegexp" ); + QString confidence = tool.readEntryUntranslated( "ScoreConfidenceRegexp" ); + SpamAgentTypes typeE = SpamAgentNone; + if ( kasciistricmp( type.data(), "bool" ) == 0 ) + typeE = SpamAgentBool; + else if ( kasciistricmp( type.data(), "decimal" ) == 0 ) + typeE = SpamAgentFloat; + else if ( kasciistricmp( type.data(), "percentage" ) == 0 ) + typeE = SpamAgentFloatLarge; + else if ( kasciistricmp( type.data(), "adjusted" ) == 0 ) + typeE = SpamAgentAdjustedFloat; + mAgents.append( SpamAgent( name, typeE, header, cheader, QRegExp( score ), + QRegExp( threshold ), QRegExp( confidence ) ) ); + } + } +} + +const SpamAgents AntiSpamConfig::uniqueAgents() const +{ + QStringList seenAgents; + SpamAgents agents; + SpamAgents::ConstIterator it( mAgents.begin() ); + SpamAgents::ConstIterator end( mAgents.end() ); + for ( ; it != end ; ++it ) { + const QString agent( ( *it ).name() ); + if ( !seenAgents.contains( agent ) ) { + agents.append( *it ); + seenAgents.append( agent ); + } + } + return agents; +} +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/antispamconfig.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/antispamconfig.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/antispamconfig.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/antispamconfig.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,122 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + antispamconfig.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Patrick Audley + Copyright (c) 2004 Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_ANTISPAMCONFIG_H__ +#define __MESSAGEVIEWER_ANTISPAMCONFIG_H__ + +#include +#include +#include "messageviewer_export.h" +class QString; +namespace MessageViewer { + +/// Valid types of SpamAgent +typedef enum { + SpamAgentNone, //!< Invalid SpamAgent, skip this agent + SpamAgentBool, //!< Simple Yes or No (Razor) + SpamAgentFloat, //!< For straight percentages between 0.0 and 1.0 (BogoFilter) + SpamAgentFloatLarge, //!< For straight percentages between 0.0 and 100.0 + SpamAgentAdjustedFloat //!< Use this when we need to compare against a threshold (SpamAssasssin) +} SpamAgentTypes; + +class SpamAgent { +public: + SpamAgent() : mType( SpamAgentNone ) {} + SpamAgent( const QString & name, SpamAgentTypes type, const QByteArray & field, const QByteArray & cfield, + const QRegExp & score, const QRegExp & threshold, const QRegExp & confidence ) + : mName( name ), mType( type ), mField( field ), mConfidenceField( cfield ), + mScore( score ), mThreshold( threshold ), mConfidence( confidence ) {} + + QString name() const { return mName; } + SpamAgentTypes scoreType() const { return mType; } + QByteArray header() const { return mField; } + QByteArray confidenceHeader() const { return mConfidenceField; } + QRegExp scorePattern() const { return mScore; } + QRegExp thresholdPattern() const { return mThreshold; } + QRegExp confidencePattern() const { return mConfidence; } + +private: + QString mName; + SpamAgentTypes mType; + QByteArray mField; + QByteArray mConfidenceField; + QRegExp mScore; + QRegExp mThreshold; + QRegExp mConfidence; +}; +typedef QList SpamAgents; +typedef QList::Iterator SpamAgentsIterator; + +class AntiSpamConfigSingletonProvider; + +/** + @short Singleton to manage loading the kmail.antispamrc file. + @author Patrick Audley + + Use of this config-manager class is straight forward. Since it + is a singleton object, all you have to do is obtain an instance + by calling @p SpamConfig::instance() and use any of the + public member functions. + */ +class MESSAGEVIEWER_EXPORT AntiSpamConfig { +friend class AntiSpamConfigSingletonProvider; +private: + AntiSpamConfig(); + +public: + ~AntiSpamConfig() {} + + static AntiSpamConfig * instance(); + + /** + * Returns a list of all agents found on the system. This + * might list SA twice, if both the C and the Perl version are present. + */ + const SpamAgents agents() const { return mAgents; } + SpamAgents agents() { return mAgents; } + + /** + * Returns a list of unique agents, found on the system. SpamAssassin will + * only be listed once, even if both the C and the Perl version are + * installed. + */ + const SpamAgents uniqueAgents() const; + +private: + SpamAgents mAgents; + + void readConfig(); +}; +} + +#endif // __MESSAGEVIEWER_ANTISPAMCONFIG_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/attachmentdialog.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/attachmentdialog.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/attachmentdialog.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/attachmentdialog.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,108 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + This file is part of KMail, the KDE mail client. + Copyright (c) 2009 Martin Koller + + 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) any later version. + + 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. +*/ + +#include + +#include +#include +#include + + +//--------------------------------------------------------------------- + +AttachmentDialog::AttachmentDialog( QWidget *parent, const QString &filenameText, + const QString &application, const QString &dontAskAgainName ) + : dontAskName( dontAskAgainName ) +{ + text = i18n( "Open attachment '%1'?\n" + "Note that opening an attachment may compromise " + "your system's security.", + filenameText ); + + dialog = new KDialog( parent ); + dialog->setCaption( i18n("Open Attachment?") ); + dialog->setObjectName( "attachmentSaveOpen" ); + + if ( application.isEmpty() ) + dialog->setButtons( KDialog::User3 | KDialog::User1 | KDialog::Cancel ); + else { + dialog->setButtons( KDialog::User3 | KDialog::User2 | KDialog::User1 | KDialog::Cancel ); + dialog->setButtonText( KDialog::User2, i18n("&Open with '%1'", application ) ); + } + + dialog->setButtonGuiItem( KDialog::User3, KStandardGuiItem::saveAs() ); + dialog->setButtonText( KDialog::User1, i18n("&Open With...") ); + dialog->setDefaultButton( KDialog::User3 ); + + connect( dialog, SIGNAL( user3Clicked() ), this, SLOT( saveClicked() ) ); + connect( dialog, SIGNAL( user2Clicked() ), this, SLOT( openClicked() ) ); + connect( dialog, SIGNAL( user1Clicked() ), this, SLOT( openWithClicked() ) ); +} + +//--------------------------------------------------------------------- + +int AttachmentDialog::exec() +{ + KConfigGroup cg( KGlobal::config().data(), "Notification Messages" ); + if ( cg.hasKey( dontAskName ) ) + return cg.readEntry( dontAskName, int(0) ); + + bool again = false; + const int ret = + KMessageBox::createKMessageBox( dialog, QMessageBox::Question, text, QStringList(), + i18n( "Do not ask again" ), &again, 0 ); + + if ( ret == QDialog::Rejected ) + return Cancel; + else { + if ( again ) { + KConfigGroup::WriteConfigFlags flags = KConfig::Persistent; + KConfigGroup cg( KGlobal::config().data(), "Notification Messages" ); + cg.writeEntry( dontAskName, ret, flags ); + cg.sync(); + } + + return ret; + } +} + +//--------------------------------------------------------------------- + +void AttachmentDialog::saveClicked() +{ + dialog->done( Save ); +} + +//--------------------------------------------------------------------- + +void AttachmentDialog::openClicked() +{ + dialog->done( Open ); +} + +//--------------------------------------------------------------------- + +void AttachmentDialog::openWithClicked() +{ + dialog->done( OpenWith ); +} + +//--------------------------------------------------------------------- + +#include "attachmentdialog.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/attachmentdialog.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/attachmentdialog.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/attachmentdialog.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/attachmentdialog.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,64 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + This file is part of KMail, the KDE mail client. + Copyright (c) 2009 Martin Koller + + 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) any later version. + + 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. +*/ + +#ifndef MESSAGEVIEWERT_ATTACHMENTDIALOG_H +#define MESSAGEVIEWERT_ATTACHMENTDIALOG_H + +#include "messageviewer_export.h" +#include + +class KDialog; + +/** A class which handles the dialog used to present the user a choice what to do + with an attachment. +*/ + +class MESSAGEVIEWER_EXPORT AttachmentDialog : public QObject +{ + Q_OBJECT + + public: + /// returncodes for exec() + enum + { + Save = 2, + Open, + OpenWith, + Cancel + }; + + // if @application is non-empty, the "open with " button will also be shown, + // otherwise only save, open with, cancel + AttachmentDialog( QWidget *parent, const QString &filenameText, const QString &application, + const QString &dontAskAgainName ); + + // executes the modal dialog + int exec(); + + private slots: + void saveClicked(); + void openClicked(); + void openWithClicked(); + + private: + QString text, dontAskName; + KDialog *dialog; +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/attachmentstrategy.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/attachmentstrategy.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/attachmentstrategy.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/attachmentstrategy.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,222 @@ +/* -*- c++ -*- + attachmentstrategy.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "attachmentstrategy.h" + +#include + +#include +#include + +namespace MessageViewer { + +// +// IconicAttachmentStrategy: +// show everything but the first text/plain body as icons +// + +class IconicAttachmentStrategy : public AttachmentStrategy { + friend class AttachmentStrategy; +protected: + IconicAttachmentStrategy() : AttachmentStrategy() {} + virtual ~IconicAttachmentStrategy() {} + +public: + const char * name() const { return "iconic"; } + const AttachmentStrategy * next() const { return smart(); } + const AttachmentStrategy * prev() const { return hidden(); } + + bool inlineNestedMessages() const { return false; } + Display defaultDisplay( KMime::Content * node ) const { + if ( node->contentType()->isText() && + node->contentDisposition()->filename().trimmed().isEmpty() && + node->contentType()->name().trimmed().isEmpty() ) + // text/* w/o filename parameter: + return Inline; + return AsIcon; + } +}; + +// +// SmartAttachmentStrategy: +// in addition to Iconic, show all body parts +// with content-disposition == "inline" and +// all text parts without a filename or name parameter inline +// + +class SmartAttachmentStrategy : public AttachmentStrategy { + friend class AttachmentStrategy; +protected: + SmartAttachmentStrategy() : AttachmentStrategy() {} + virtual ~SmartAttachmentStrategy() {} + +public: + const char * name() const { return "smart"; } + const AttachmentStrategy * next() const { return inlined(); } + const AttachmentStrategy * prev() const { return iconic(); } + + bool inlineNestedMessages() const { return true; } + Display defaultDisplay( KMime::Content * node ) const { + if ( node->contentDisposition()->disposition() == KMime::Headers::CDinline ) + // explict "inline" disposition: + return Inline; + if ( node->contentDisposition()->disposition() == KMime::Headers::CDattachment) + // explicit "attachment" disposition: + return AsIcon; + if ( node->contentType()->isText() && + node->contentDisposition()->filename().trimmed().isEmpty() && + node->contentType()->name().trimmed().isEmpty() ) + // text/* w/o filename parameter: + return Inline; + return AsIcon; + } +}; + +// +// InlinedAttachmentStrategy: +// show everything possible inline +// + +class InlinedAttachmentStrategy : public AttachmentStrategy { + friend class AttachmentStrategy; +protected: + InlinedAttachmentStrategy() : AttachmentStrategy() {} + virtual ~InlinedAttachmentStrategy() {} + +public: + const char * name() const { return "inlined"; } + const AttachmentStrategy * next() const { return hidden(); } + const AttachmentStrategy * prev() const { return smart(); } + + bool inlineNestedMessages() const { return true; } + Display defaultDisplay( KMime::Content * ) const { return Inline; } +}; + +// +// HiddenAttachmentStrategy +// show nothing except the first text/plain body part _at all_ +// + +class HiddenAttachmentStrategy : public AttachmentStrategy { + friend class AttachmentStrategy; +protected: + HiddenAttachmentStrategy() : AttachmentStrategy() {} + virtual ~HiddenAttachmentStrategy() {} + +public: + const char * name() const { return "hidden"; } + const AttachmentStrategy * next() const { return iconic(); } + const AttachmentStrategy * prev() const { return inlined(); } + + bool inlineNestedMessages() const { return false; } + Display defaultDisplay( KMime::Content * node ) const { + if ( node->contentType()->isText() && + node->contentDisposition()->filename().trimmed().isEmpty() && + node->contentType()->name().trimmed().isEmpty() ) + // text/* w/o filename parameter: + return Inline; + + if ( node->parent() && node->parent()->contentType()->isMultipart() && + node->parent()->contentType()->subType() == "related" ) + return Inline; + + return None; + } +}; + + +// +// AttachmentStrategy abstract base: +// + +AttachmentStrategy::AttachmentStrategy() { + +} + +AttachmentStrategy::~AttachmentStrategy() { + +} + +const AttachmentStrategy * AttachmentStrategy::create( Type type ) { + switch ( type ) { + case Iconic: return iconic(); + case Smart: return smart(); + case Inlined: return inlined(); + case Hidden: return hidden(); + } + kFatal( 5006 ) << "Unknown attachment startegy ( type ==" + << (int)type << ") requested!"; + return 0; // make compiler happy +} + +const AttachmentStrategy * AttachmentStrategy::create( const QString & type ) { + QString lowerType = type.toLower(); + if ( lowerType == "iconic" ) return iconic(); + //if ( lowerType == "smart" ) return smart(); // not needed, see below + if ( lowerType == "inlined" ) return inlined(); + if ( lowerType == "hidden" ) return hidden(); + // don't kFatal here, b/c the strings are user-provided + // (KConfig), so fail gracefully to the default: + return smart(); +} + +static const AttachmentStrategy * iconicStrategy = 0; +static const AttachmentStrategy * smartStrategy = 0; +static const AttachmentStrategy * inlinedStrategy = 0; +static const AttachmentStrategy * hiddenStrategy = 0; + +const AttachmentStrategy * AttachmentStrategy::iconic() { + if ( !iconicStrategy ) + iconicStrategy = new IconicAttachmentStrategy(); + return iconicStrategy; +} + +const AttachmentStrategy * AttachmentStrategy::smart() { + if ( !smartStrategy ) + smartStrategy = new SmartAttachmentStrategy(); + return smartStrategy; +} + +const AttachmentStrategy * AttachmentStrategy::inlined() { + if ( !inlinedStrategy ) + inlinedStrategy = new InlinedAttachmentStrategy(); + return inlinedStrategy; +} + +const AttachmentStrategy * AttachmentStrategy::hidden() { + if ( !hiddenStrategy ) + hiddenStrategy = new HiddenAttachmentStrategy(); + return hiddenStrategy; +} + +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/attachmentstrategy.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/attachmentstrategy.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/attachmentstrategy.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/attachmentstrategy.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,85 @@ +/* -*- c++ -*- + attachmentstrategy.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_ATTACHMENTSTRATEGY_H__ +#define __MESSAGEVIEWER_ATTACHMENTSTRATEGY_H__ + +#include "messageviewer_export.h" + +class QString; +namespace KMime { + class Content; +} + +namespace MessageViewer { + +class MESSAGEVIEWER_EXPORT AttachmentStrategy { +protected: + AttachmentStrategy(); + virtual ~AttachmentStrategy(); + +public: + // + // Factory methods: + // + enum Type { Iconic, Smart, Inlined, Hidden }; + + static const AttachmentStrategy * create( Type type ); + static const AttachmentStrategy * create( const QString & type ); + + static const AttachmentStrategy * iconic(); + static const AttachmentStrategy * smart(); + static const AttachmentStrategy * inlined(); + static const AttachmentStrategy * hidden(); + + // + // Navigation methods: + // + + virtual const char * name() const = 0; + virtual const AttachmentStrategy * next() const = 0; + virtual const AttachmentStrategy * prev() const = 0; + + // + // Bahavioural: + // + + enum Display { None, AsIcon, Inline }; + + virtual bool inlineNestedMessages() const = 0; + virtual Display defaultDisplay( KMime::Content * node ) const = 0; +}; + +} + +#endif // __MESSAGEVIEWER_ATTACHMENTSTRATEGY_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/autoqpointer.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/autoqpointer.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/autoqpointer.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/autoqpointer.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,45 @@ +/* + * autoqpointer.h - QPointer which on destruction deletes object + * This is a (mostly) verbatim, private copy of kdepim/kalarm/lib/autoqpointer.h + * + * Copyright © 2009 by David Jarvie + * + * 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) any later version. + * + * 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. + */ + +#ifndef AUTOQPOINTER_H +#define AUTOQPOINTER_H + +#include + + +/** + * A QPointer which when destructed, deletes the object it points to. + * + * @author David Jarvie + */ +template +class AutoQPointer : public QPointer +{ + public: + inline AutoQPointer() : QPointer() {} + inline AutoQPointer(T* p) : QPointer(p) {} + inline AutoQPointer(const QPointer& p) : QPointer(p) {} + inline ~AutoQPointer() { delete this->data(); } + inline AutoQPointer& operator=(const AutoQPointer& p) { QPointer::operator=(p); return *this; } + inline AutoQPointer& operator=(T* p) { QPointer::operator=(p); return *this; } +}; + +#endif // AUTOQPOINTER_H diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatter.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatter.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatter.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatter.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,324 @@ +/* -*- c++ -*- + bodypartformatter.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + + +#include "bodypartformatter.h" +#include "bodypartformatterfactory_p.h" +#include "interfaces/bodypartformatter.h" + +#include "objecttreeparser.h" + +#include + +#include +#include + +using namespace MessageViewer; + +namespace { + class AnyTypeBodyPartFormatter + : public BodyPartFormatter, + public MessageViewer::Interface::BodyPartFormatter { + static const AnyTypeBodyPartFormatter * self; + public: + Result format( Interface::BodyPart *, HtmlWriter * ) const { + kDebug() << "Acting as a Interface::BodyPartFormatter!"; + return AsIcon; + } + + bool process( ObjectTreeParser *, KMime::Content *, ProcessResult & result ) const { + result.setNeverDisplayInline( true ); + return false; + } + static const ::BodyPartFormatter * create() { + if ( !self ) + self = new AnyTypeBodyPartFormatter(); + return self; + } + }; + + const AnyTypeBodyPartFormatter * AnyTypeBodyPartFormatter::self = 0; + + + class ImageTypeBodyPartFormatter : public BodyPartFormatter { + static const ImageTypeBodyPartFormatter * self; + public: + bool process( ObjectTreeParser *, KMime::Content *, ProcessResult & result ) const { + result.setIsImage( true ); + return false; + } + static const BodyPartFormatter * create() { + if ( !self ) + self = new ImageTypeBodyPartFormatter(); + return self; + } + }; + + const ImageTypeBodyPartFormatter * ImageTypeBodyPartFormatter::self = 0; + +#define CREATE_BODY_PART_FORMATTER(subtype) \ + class subtype##BodyPartFormatter : public BodyPartFormatter { \ + static const subtype##BodyPartFormatter * self; \ + public: \ + bool process( ObjectTreeParser *, KMime::Content *, ProcessResult & ) const; \ + static const BodyPartFormatter * create() { \ + if ( !self ) \ + self = new subtype##BodyPartFormatter(); \ + return self; \ + } \ + }; \ + \ + const subtype##BodyPartFormatter * subtype##BodyPartFormatter::self; \ + \ + bool subtype##BodyPartFormatter::process( ObjectTreeParser * otp, KMime::Content * node, ProcessResult & result ) const { \ + return otp->process##subtype##Subtype( node, result ); \ + } + + + CREATE_BODY_PART_FORMATTER(TextPlain) + CREATE_BODY_PART_FORMATTER(TextHtml) + //CREATE_BODY_PART_FORMATTER(TextEnriched) + + CREATE_BODY_PART_FORMATTER(ApplicationOctetStream) + CREATE_BODY_PART_FORMATTER(ApplicationPkcs7Mime) + CREATE_BODY_PART_FORMATTER(ApplicationChiasmusText) + //CREATE_BODY_PART_FORMATTER(ApplicationPgp) + CREATE_BODY_PART_FORMATTER(ApplicationMsTnef) + + CREATE_BODY_PART_FORMATTER(MessageRfc822) + + CREATE_BODY_PART_FORMATTER(MultiPartMixed) + CREATE_BODY_PART_FORMATTER(MultiPartAlternative) + CREATE_BODY_PART_FORMATTER(MultiPartSigned) + CREATE_BODY_PART_FORMATTER(MultiPartEncrypted) + + typedef TextPlainBodyPartFormatter ApplicationPgpBodyPartFormatter; + + +#undef CREATE_BODY_PART_FORMATTER +} // anon namespace + +// FIXME: port some more BodyPartFormatters to Interface::BodyPartFormatters +void BodyPartFormatterFactoryPrivate::kmail_create_builtin_bodypart_formatters( BodyPartFormatterFactoryPrivate::TypeRegistry * reg ) { + if ( !reg ) return; + (*reg)["application"]["octet-stream"] = new AnyTypeBodyPartFormatter(); +} + +typedef const BodyPartFormatter * (*BodyPartFormatterCreator)(); + +struct SubtypeBuiltin { + const char * subtype; + BodyPartFormatterCreator create; +}; + +static const SubtypeBuiltin applicationSubtypeBuiltins[] = { + { "octet-stream", &ApplicationOctetStreamBodyPartFormatter::create }, + { "pkcs7-mime", &ApplicationPkcs7MimeBodyPartFormatter::create }, + { "x-pkcs7-mime", &ApplicationPkcs7MimeBodyPartFormatter::create }, + { "vnd.de.bund.bsi.chiasmus-text", &ApplicationChiasmusTextBodyPartFormatter::create }, + { "pgp", &ApplicationPgpBodyPartFormatter::create }, + { "ms-tnef", &ApplicationMsTnefBodyPartFormatter::create } +}; + +static const SubtypeBuiltin textSubtypeBuiltins[] = { + { "html", &TextHtmlBodyPartFormatter::create }, + //{ "enriched", &TextEnrichedBodyPartFormatter::create }, + { "x-vcard", &AnyTypeBodyPartFormatter::create }, + { "vcard", &AnyTypeBodyPartFormatter::create }, + { "rtf", &AnyTypeBodyPartFormatter::create }, + { "*", &TextPlainBodyPartFormatter::create }, +}; + +static const SubtypeBuiltin multipartSubtypeBuiltins[] = { + { "mixed", &MultiPartMixedBodyPartFormatter::create }, + { "alternative", &MultiPartAlternativeBodyPartFormatter::create }, + //{ "digest", &MultiPartDigestFormatter::create }, + //{ "parallel", &MultiPartParallelFormatter::create }, + //{ "related", &MultiPartRelatedFormatter::create }, + { "signed", &MultiPartSignedBodyPartFormatter::create }, + { "encrypted", &MultiPartEncryptedBodyPartFormatter::create }, + //{ "report", &MultiPartReportFormatter::create }, +}; + +static const SubtypeBuiltin messageSubtypeBuiltins[] = { + { "rfc822", &MessageRfc822BodyPartFormatter::create }, +}; + +static const SubtypeBuiltin imageSubtypeBuiltins[] = { + { "*", &ImageTypeBodyPartFormatter::create }, +}; + +static const SubtypeBuiltin anySubtypeBuiltins[] = { + { "*", &AnyTypeBodyPartFormatter::create }, +}; + +#ifdef DIM +#undef DIM +#endif +#define DIM(x) sizeof(x) / sizeof(*x) + +static const struct { + const char * type; + const SubtypeBuiltin * subtypes; + unsigned int num_subtypes; +} builtins[] = { + { "application", applicationSubtypeBuiltins, DIM(applicationSubtypeBuiltins) }, + { "text", textSubtypeBuiltins, DIM(textSubtypeBuiltins) }, + { "multipart", multipartSubtypeBuiltins, DIM(multipartSubtypeBuiltins) }, + { "message", messageSubtypeBuiltins, DIM(messageSubtypeBuiltins) }, + { "image", imageSubtypeBuiltins, DIM(imageSubtypeBuiltins) }, + //{ "audio", audioSubtypeBuiltins, DIM(audioSubtypeBuiltins) }, + //{ "model", modelSubtypeBuiltins, DIM(modelSubtypeBuiltins) }, + //{ "video", videoSubtypeBuiltins, DIM(videoSubtypeBuiltins) }, + { "*", anySubtypeBuiltins, DIM(anySubtypeBuiltins) }, +}; + +#undef DIM + +static const BodyPartFormatter * createForText( const char * subtype ) { + if ( subtype && *subtype ) + switch ( subtype[0] ) { + case 'h': + case 'H': + if ( kasciistricmp( subtype, "html" ) == 0 ) + return TextHtmlBodyPartFormatter::create(); + break; + case 'r': + case 'R': + if ( kasciistricmp( subtype, "rtf" ) == 0 ) + return AnyTypeBodyPartFormatter::create(); + break; + case 'x': + case 'X': + case 'v': + case 'V': + if ( kasciistricmp( subtype, "x-vcard" ) == 0 || + kasciistricmp( subtype, "vcard" ) == 0 ) + return AnyTypeBodyPartFormatter::create(); + break; + } + + return TextPlainBodyPartFormatter::create(); +} + +static const BodyPartFormatter * createForImage( const char * ) { + return ImageTypeBodyPartFormatter::create(); +} + +static const BodyPartFormatter * createForMessage( const char * subtype ) { + if ( kasciistricmp( subtype, "rfc822" ) == 0 ) + return MessageRfc822BodyPartFormatter::create(); + return AnyTypeBodyPartFormatter::create(); +} + +static const BodyPartFormatter * createForMultiPart( const char * subtype ) { + if ( subtype && *subtype ) + switch ( subtype[0] ) { + case 'a': + case 'A': + if ( kasciistricmp( subtype, "alternative" ) == 0 ) + return MultiPartAlternativeBodyPartFormatter::create(); + break; + case 'e': + case 'E': + if ( kasciistricmp( subtype, "encrypted" ) == 0 ) + return MultiPartEncryptedBodyPartFormatter::create(); + break; + case 's': + case 'S': + if ( kasciistricmp( subtype, "signed" ) == 0 ) + return MultiPartSignedBodyPartFormatter::create(); + break; + } + + return MultiPartMixedBodyPartFormatter::create(); +} + +static const BodyPartFormatter * createForApplication( const char * subtype ) { + if ( subtype && *subtype ) + switch ( subtype[0] ) { + case 'p': + case 'P': + if ( kasciistricmp( subtype, "pgp" ) == 0 ) + return ApplicationPgpBodyPartFormatter::create(); + // fall through + case 'x': + case 'X': + if ( kasciistricmp( subtype, "pkcs7-mime" ) == 0 || + kasciistricmp( subtype, "x-pkcs7-mime" ) == 0 ) + return ApplicationPkcs7MimeBodyPartFormatter::create(); + break; + case 'm': + case 'M': + if ( kasciistricmp( subtype, "ms-tnef" ) == 0 ) + return ApplicationMsTnefBodyPartFormatter::create(); + break; + case 'v': + case 'V': + if ( kasciistricmp( subtype, "vnd.de.bund.bsi.chiasmus-text") == 0) + return ApplicationChiasmusTextBodyPartFormatter::create(); + break; + } + + return AnyTypeBodyPartFormatter::create(); +} + +// OK, replace this with a factory with plugin support later on... +const BodyPartFormatter * BodyPartFormatter::createFor( const char * type, const char * subtype ) { + if ( type && *type ) + switch ( type[0] ) { + case 'a': // application + case 'A': + if ( kasciistricmp( type, "application" ) == 0 ) + return createForApplication( subtype ); + break; + case 'i': // image + case 'I': + if ( kasciistricmp( type, "image" ) == 0 ) + return createForImage( subtype ); + break; + case 'm': // multipart / message + case 'M': + if ( kasciistricmp( type, "multipart" ) == 0 ) + return createForMultiPart( subtype ); + else if ( kasciistricmp( type, "message" ) == 0 ) + return createForMessage( subtype ); + break; + case 't': // text + case 'T': + if ( kasciistricmp( type, "text" ) == 0 ) + return createForText( subtype ); + break; + } + + return AnyTypeBodyPartFormatter::create(); +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatterfactory.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatterfactory.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatterfactory.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatterfactory.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,194 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + bodypartformatterfactory.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Marc Mutz , + Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + + +#include "bodypartformatterfactory.h" +#include "bodypartformatterfactory_p.h" +using namespace BodyPartFormatterFactoryPrivate; + +#include "interfaces/bodypartformatter.h" +#include "urlhandlermanager.h" + +// libkdepim +#include + +// KDE +#include + +// Qt +#include +#include + +#include + +using namespace MessageViewer; + +namespace { + + KPIM_DEFINE_PLUGIN_LOADER( BodyPartFormatterPluginLoader, + Interface::BodyPartFormatterPlugin, + "create_bodypart_formatter_plugin", + "kmail/plugins/bodypartformatter/*.desktop" ) + +} + +BodyPartFormatterFactory * BodyPartFormatterFactory::mSelf = 0; + +const BodyPartFormatterFactory * BodyPartFormatterFactory::instance() { + if ( !mSelf ) + mSelf = new BodyPartFormatterFactory(); + return mSelf; +} + +BodyPartFormatterFactory::BodyPartFormatterFactory() { + mSelf = this; +} + +BodyPartFormatterFactory::~BodyPartFormatterFactory() { + mSelf = 0; +} + +static TypeRegistry * all = 0; + +static void insertBodyPartFormatter( const char * type, const char * subtype, + const Interface::BodyPartFormatter * formatter ) { + if ( !type || !*type || !subtype || !*subtype || !formatter || !all ) + return; + + TypeRegistry::iterator type_it = all->find( type ); + if ( type_it == all->end() ) { + kDebug() <<"BodyPartFormatterFactory: instantiating new Subtype Registry for \"" + << type << "\""; + type_it = all->insert( std::make_pair( type, SubtypeRegistry() ) ).first; + assert( type_it != all->end() ); + } + + SubtypeRegistry & subtype_reg = type_it->second; + SubtypeRegistry::iterator subtype_it = subtype_reg.find( subtype ); + if ( subtype_it != subtype_reg.end() ) { + kDebug() <<"BodyPartFormatterFactory: overwriting previously registered formatter for \"" + << type << "/" << subtype << "\""; + subtype_reg.erase( subtype_it ); subtype_it = subtype_reg.end(); + } + + subtype_reg.insert( std::make_pair( subtype, formatter ) ); +} + +static void loadPlugins() { + const BodyPartFormatterPluginLoader * pl = BodyPartFormatterPluginLoader::instance(); + if ( !pl ) { + kWarning() <<"BodyPartFormatterFactory: cannot instantiate plugin loader!"; + return; + } + const QStringList types = pl->types(); + kDebug() <<"BodyPartFormatterFactory: found" << types.size() <<" plugins."; + for ( QStringList::const_iterator it = types.begin() ; it != types.end() ; ++it ) { + const Interface::BodyPartFormatterPlugin * plugin = pl->createForName( *it ); + if ( !plugin ) { + kWarning() <<"BodyPartFormatterFactory: plugin \"" << *it <<"\" is not valid!"; + continue; + } + const Interface::BodyPartFormatter * bfp; + for ( int i = 0 ; (bfp = plugin->bodyPartFormatter( i )) ; ++i ) { + const char * type = plugin->type( i ); + if ( !type || !*type ) { + kWarning() <<"BodyPartFormatterFactory: plugin \"" << *it + << "\" returned empty type specification for index" + << i; + break; + } + const char * subtype = plugin->subtype( i ); + if ( !subtype || !*subtype ) { + kWarning() <<"BodyPartFormatterFactory: plugin \"" << *it + << "\" returned empty subtype specification for index" + << i; + break; + } + insertBodyPartFormatter( type, subtype, bfp ); + } + const Interface::BodyPartURLHandler * handler; + for ( int i = 0 ; (handler = plugin->urlHandler( i )) ; ++i ) + URLHandlerManager::instance()->registerHandler( handler ); + } +} + +static void setup() { + if ( !all ) { + all = new TypeRegistry(); + kmail_create_builtin_bodypart_formatters( all ); + loadPlugins(); + } +} + +const Interface::BodyPartFormatter * BodyPartFormatterFactory::createFor( const char * type, const char * subtype ) const { + if ( !type || !*type ) + type = "*"; //krazy:exclude=doublequote_chars + if ( !subtype || !*subtype ) + subtype = "*"; //krazy:exclude=doublequote_chars + + setup(); + assert( all ); + + if ( all->empty() ) + return 0; + + TypeRegistry::const_iterator type_it = all->find( type ); + if ( type_it == all->end() ) + type_it = all->find( "*" ); + if ( type_it == all->end() ) + return 0; + + const SubtypeRegistry & subtype_reg = type_it->second; + if ( subtype_reg.empty() ) + return 0; + + SubtypeRegistry::const_iterator subtype_it = subtype_reg.find( subtype ); + if ( subtype_it == subtype_reg.end() ) + subtype_it = subtype_reg.find( "*" ); + if ( subtype_it == subtype_reg.end() ) + return 0; + + kWarning( !(*subtype_it).second, 5006 ) + << "BodyPartFormatterFactory: a null bodypart formatter sneaked in for \"" + << type << "/" << subtype << "\"!"; + + return (*subtype_it).second; +} + +const Interface::BodyPartFormatter * BodyPartFormatterFactory::createFor( const QString & type, const QString & subtype ) const { + return createFor( type.toLatin1(), subtype.toLatin1() ); +} + +const Interface::BodyPartFormatter * BodyPartFormatterFactory::createFor( const QByteArray & type, const QByteArray & subtype ) const { + return createFor( type.data(), subtype.data() ); +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatterfactory.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatterfactory.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatterfactory.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatterfactory.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,72 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + bodypartformatterfactory.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Marc Mutz , + Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_BODYPARTFORMATTERFACTORY_H__ +#define __MESSAGEVIEWER_BODYPARTFORMATTERFACTORY_H__ + +class QString; +#include + +namespace MessageViewer { + +namespace Interface { + class BodyPartFormatter; +} + +class BodyPartFormatterFactory { + class gcc_shut_up; + friend class BodyPartFormatterFactory::gcc_shut_up; +public: + ~BodyPartFormatterFactory(); + + static const BodyPartFormatterFactory * instance(); + + const Interface::BodyPartFormatter * createFor( const char * type, const char * subtype ) const; + const Interface::BodyPartFormatter * createFor( const QString & type, const QString & subtype ) const; + const Interface::BodyPartFormatter * createFor( const QByteArray & type, const QByteArray & subtype ) const; + + // + // Only boring stuff below: + // +private: + BodyPartFormatterFactory(); + static BodyPartFormatterFactory * mSelf; +private: + // disabled + const BodyPartFormatterFactory & operator=( const BodyPartFormatterFactory & ); + BodyPartFormatterFactory( const BodyPartFormatterFactory & ); +}; + +} + +#endif // __MESSAGEVIEWER_BODYPARTFORMATTERFACTORY_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatterfactory_p.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatterfactory_p.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatterfactory_p.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatterfactory_p.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,61 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + bodypartformatterfactory.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Marc Mutz , + Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_BODYPARTFORMATTERFACTORY_P_H__ +#define __MESSAGEVIEWER_BODYPARTFORMATTERFACTORY_P_H__ + + +#include +#include + +namespace MessageViewer { + namespace Interface { + class BodyPartFormatter; + } +} + +namespace BodyPartFormatterFactoryPrivate { + struct ltstr { + bool operator()( const char * s1, const char * s2 ) const { +return qstricmp( s1, s2 ) < 0; + } + }; + + typedef std::map SubtypeRegistry; + typedef std::map TypeRegistry; + + // defined in bodypartformatters.cpp + extern void kmail_create_builtin_bodypart_formatters( TypeRegistry * ); +} + +#endif // __MESSAGEVIEWER_BODYPARTFORMATTERFACTORY_P_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatter.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatter.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/bodypartformatter.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/bodypartformatter.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,59 @@ +/* -*- c++ -*- + bodypartformatter.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_BODYPARTFORMATTER_H__ +#define __MESSAGEVIEWER_BODYPARTFORMATTER_H__ + +namespace KMime { + class Content; +} + +namespace MessageViewer { + class ObjectTreeParser; + class ProcessResult; +} + + +class BodyPartFormatter { + const BodyPartFormatter & operator=( const BodyPartFormatter & ); + BodyPartFormatter( const BodyPartFormatter & ); +protected: + BodyPartFormatter() {} +public: + virtual ~BodyPartFormatter() {} + + virtual bool process( MessageViewer::ObjectTreeParser *, KMime::Content *, MessageViewer::ProcessResult & ) const = 0; + + static const BodyPartFormatter * createFor( const char * type, const char * subtype ); +}; + + +#endif // __MESSAGEVIEWER_BODYPARTFORMATTER_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/CMakeLists.txt 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,71 @@ +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) + +add_subdirectory(tests) + +set(libmessageviewer_SRCS + +viewer_p.cpp +viewer.cpp +khtmlparthtmlwriter.cpp +htmlstatusbar.cpp +headerstyle.cpp +headerstrategy.cpp +kmaddrbook.cpp +stringutil.cpp +attachmentstrategy.cpp +kmmsgpartdlg.cpp +csshelper.cpp +util.cpp +objecttreeparser_p.cpp +objecttreeparser.cpp +kleojobexecutor.cpp +bodypartformatter.cpp +bodypartformatterfactory.cpp +partnodebodypart.cpp +nodehelper.cpp +urlhandlermanager.cpp +vcardviewer.cpp +iconnamecache.cpp +mailsourceviewer.cpp +mimetreemodel.cpp +global.cpp +spamheaderanalyzer.cpp +antispamconfig.cpp +globalsettings.cpp +configurewidget.cpp +htmlquotecolorer.cpp +editorwatcher.cpp +attachmentdialog.cpp +objecttreeviewersource.cpp +objecttreeemptysource.cpp +filehtmlwriter.cpp +teehtmlwriter.cpp +) + + +kde4_add_kcfg_files(libmessageviewer_SRCS + globalsettings_base.kcfgc +) + +kde4_add_ui_files(libmessageviewer_SRCS + settings.ui +) + +kde4_add_library(messageviewer SHARED ${libmessageviewer_SRCS}) + + +target_link_libraries(messageviewer messagecore kdepim kpgp kleo + ${KDEPIMLIBS_KMIME_LIBS} ${KDEPIMLIBS_AKONADI_LIIBS} + ${KDE4_KDEUI_LIBS} ${KDE4_KHTML_LIBS} ${KDE4_KTNEF_LIBRARY} + ${QGPGME_LIBRARIES} ${KDE4_KDE3SUPPORT_LIBS} +) + +include_directories( + ${CMAKE_SOURCE_DIR}/libkleo + ${Boost_INCLUDE_DIRS} + ${GPGME_INCLUDES} +) + +install(TARGETS messageviewer ${INSTALL_TARGETS_DEFAULT_ARGS} ) + +#install( FILES viewer.h attachmentstrategy.h headerstrategy.h messageviewer_export.h DESTINATION ${INCLUDE_INSTALL_DIR}/messageviewer COMPONENT devel) diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/configurewidget.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/configurewidget.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/configurewidget.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/configurewidget.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,120 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#include "configurewidget.h" +#include "ui_settings.h" +#include "util.h" +#include "globalsettings.h" + +ConfigureWidget::ConfigureWidget( QWidget *parent ) + : QWidget(parent) +{ + mSettingsUi = new Ui_Settings; + mSettingsUi->setupUi( this ); + QStringList encodings = Util::supportedEncodings( false ); + mSettingsUi->kcfg_FallbackCharacterEncoding->addItems( encodings ); + QString fallbackCharsetWhatsThis = + i18n( GlobalSettings::self()->fallbackCharacterEncodingItem()->whatsThis().toUtf8() ); + mSettingsUi->kcfg_FallbackCharacterEncoding->setWhatsThis( fallbackCharsetWhatsThis ); + + encodings.prepend( i18n( "Auto" ) ); + mSettingsUi->kcfg_OverrideCharacterEncoding->addItems( encodings ); + mSettingsUi->kcfg_OverrideCharacterEncoding->setCurrentIndex(0); + + QString overrideCharsetWhatsThis = + i18n( GlobalSettings::self()->overrideCharacterEncodingItem()->whatsThis().toUtf8() ); + mSettingsUi->kcfg_OverrideCharacterEncoding->setWhatsThis( overrideCharsetWhatsThis ); + + readCurrentFallbackCodec(); + readCurrentOverrideCodec(); +} + + +ConfigureWidget::~ConfigureWidget() +{ + delete mSettingsUi; + mSettingsUi = 0; +} + +void ConfigureWidget::readCurrentFallbackCodec() +{ + QStringList encodings = Util::supportedEncodings( false ); + QStringList::ConstIterator it( encodings.begin() ); + QStringList::ConstIterator end( encodings.end() ); + QString currentEncoding = GlobalSettings::self()->fallbackCharacterEncoding(); + uint i = 0; + int indexOfLatin9 = 0; + bool found = false; + for( ; it != end; ++it) + { + const QString encoding = Util::encodingForName(*it); + if ( encoding == "ISO-8859-15" ) + indexOfLatin9 = i; + if( encoding == currentEncoding ) + { + mSettingsUi->kcfg_FallbackCharacterEncoding->setCurrentIndex( i ); + found = true; + break; + } + i++; + } + if ( !found ) // nothing matched, use latin9 + mSettingsUi->kcfg_FallbackCharacterEncoding->setCurrentIndex( indexOfLatin9 ); +} + +void ConfigureWidget::readCurrentOverrideCodec() +{ + const QString ¤tOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding(); + if ( currentOverrideEncoding.isEmpty() ) { + mSettingsUi->kcfg_OverrideCharacterEncoding->setCurrentIndex( 0 ); + return; + } + QStringList encodings = Util::supportedEncodings( false ); + encodings.prepend( i18n( "Auto" ) ); + QStringList::ConstIterator it( encodings.constBegin() ); + QStringList::ConstIterator end( encodings.constEnd() ); + int i = 0; + for( ; it != end; ++it) + { + if( Util::encodingForName(*it) == currentOverrideEncoding ) + { + mSettingsUi->kcfg_OverrideCharacterEncoding->setCurrentIndex( i ); + break; + } + i++; + } + if ( i == encodings.size() ) { + // the current value of overrideCharacterEncoding is an unknown encoding => reset to Auto + kWarning() <<"Unknown override character encoding \"" << currentOverrideEncoding + << "\". Resetting to Auto."; + mSettingsUi->kcfg_OverrideCharacterEncoding->setCurrentIndex( 0 ); + GlobalSettings::self()->setOverrideCharacterEncoding( QString() ); + } +} + + +void ConfigureWidget::slotSettingsChanged() +{ + GlobalSettings::self()->setOverrideCharacterEncoding( Util::encodingForName( mSettingsUi->kcfg_OverrideCharacterEncoding->currentText() ) ); + GlobalSettings::self()->setFallbackCharacterEncoding( Util::encodingForName( mSettingsUi->kcfg_FallbackCharacterEncoding->currentText() ) ); + emit settingsChanged(); +} + + +#include "configurewidget.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/configurewidget.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/configurewidget.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/configurewidget.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/configurewidget.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,58 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#ifndef MAILVIEWERCONFIGUREWIDGET_H +#define MAILVIEWERCONFIGUREWIDGET_H + +#include "messageviewer_export.h" + +#include +class Ui_Settings; + + +/** +Configure widget that can be used in a KConfigDialog. + + @author Andras Mantia +*/ +class MESSAGEVIEWER_EXPORT ConfigureWidget : public QWidget +{ +Q_OBJECT +public: + ConfigureWidget(QWidget *parent = 0); + + ~ConfigureWidget(); + +private slots: + void slotSettingsChanged(); + +signals: + void settingsChanged(); + +private: + void readCurrentFallbackCodec(); + void readCurrentOverrideCodec(); + + Ui_Settings *mSettingsUi; + +}; + + + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/csshelper.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/csshelper.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/csshelper.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/csshelper.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,106 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + csshelper.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + + +#include "csshelper.h" +#include "global.h" +#include "globalsettings.h" + +#include +#include +#include +#include + +#include +#include +#include + +namespace MessageViewer { + +CSSHelper::CSSHelper( const QPaintDevice *pd ) : + KPIM::CSSHelper( pd ) +{ + KSharedConfigPtr config = Global::instance()->config(); + + KConfigGroup reader( config, "Reader" ); + KConfigGroup fonts( config, "Fonts" ); + KConfigGroup pixmaps( config, "Pixmaps" ); + + mRecycleQuoteColors = reader.readEntry( "RecycleQuoteColors", false ); + + mForegroundColor = KColorScheme( QPalette::Active ).foreground().color(); + mBackgroundColor = KColorScheme( QPalette::Active ).background().color(); + if ( !reader.readEntry( "defaultColors", true ) ) { + mLinkColor = + reader.readEntry( "LinkColor", mLinkColor ); + mVisitedLinkColor = + reader.readEntry( "FollowedColor", mVisitedLinkColor ); + cPgpEncrH = + reader.readEntry( "PGPMessageEncr", cPgpEncrH ); + cPgpOk1H = + reader.readEntry( "PGPMessageOkKeyOk", cPgpOk1H ); + cPgpOk0H = + reader.readEntry( "PGPMessageOkKeyBad", cPgpOk0H ); + cPgpWarnH = + reader.readEntry( "PGPMessageWarn", cPgpWarnH ); + cPgpErrH = + reader.readEntry( "PGPMessageErr", cPgpErrH ); + cHtmlWarning = + reader.readEntry( "HTMLWarningColor", cHtmlWarning ); + for ( int i = 0 ; i < 3 ; ++i ) { + const QString key = "QuotedText" + QString::number( i+1 ); + mQuoteColor[i] = reader.readEntry( key, mQuoteColor[i] ); + } + } + + if ( !fonts.readEntry( "defaultFonts", true ) ) { + mBodyFont = fonts.readEntry( "body-font", mBodyFont ); + mPrintFont = fonts.readEntry( "print-font", mPrintFont ); + mFixedFont = fonts.readEntry( "fixed-font", mFixedFont ); + mFixedPrintFont = mFixedFont; // FIXME when we have a separate fixed print font + QFont defaultFont = mBodyFont; + defaultFont.setItalic( true ); + for ( int i = 0 ; i < 3 ; ++i ) { + const QString key = QString( "quote%1-font" ).arg( i+1 ); + mQuoteFont[i] = fonts.readEntry( key, defaultFont ); + } + } + + mShrinkQuotes = GlobalSettings::self()->shrinkQuotes(); + + mBackingPixmapStr = pixmaps.readPathEntry("Readerwin", QString()); + mBackingPixmapOn = !mBackingPixmapStr.isEmpty(); + + recalculatePGPColors(); +} + +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/csshelper.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/csshelper.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/csshelper.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/csshelper.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,47 @@ +/* -*- c++ -*- + csshelper.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_CSSHELPER_H__ +#define __MESSAGEVIEWER_CSSHELPER_H__ + +#include + +#include "messageviewer_export.h" + +namespace MessageViewer { +class MESSAGEVIEWER_EXPORT CSSHelper : public KPIM::CSSHelper { +public: + CSSHelper( const QPaintDevice *pd ); +}; + +} + +#endif // __MESSAGEVIEWER_CSSHELPER_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/editorwatcher.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/editorwatcher.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/editorwatcher.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/editorwatcher.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,166 @@ +/* + Copyright (c) 2007 Volker Krause + + 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) any later version. + + 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. +*/ + +#include "editorwatcher.h" +#include "autoqpointer.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +// inotify stuff taken from kdelibs/kio/kio/kdirwatch.cpp +#ifdef HAVE_SYS_INOTIFY_H +#include +#include +#include +#include +#endif + +namespace MessageViewer { +EditorWatcher::EditorWatcher( const KUrl & url, const QString &mimeType, bool openWith, + QObject * parent, QWidget *parentWidget ) : + QObject( parent ), + mUrl( url ), + mMimeType( mimeType ), + mOpenWith( openWith ), + mEditor( 0 ), + mParentWidget( parentWidget ), + mHaveInotify( false ), + mFileOpen( false ), + mEditorRunning( false ), + mFileModified( true ), // assume the worst unless we know better + mDone( false ) +{ + assert( mUrl.isLocalFile() ); + mTimer.setSingleShot( true ); + connect( &mTimer, SIGNAL(timeout()), SLOT(checkEditDone()) ); +} + +bool EditorWatcher::start() +{ + // find an editor + KUrl::List list; + list.append( mUrl ); + KService::Ptr offer = KMimeTypeTrader::self()->preferredService( mMimeType, "Application" ); + if ( mOpenWith || !offer ) { + AutoQPointer dlg( new KOpenWithDialog( list, i18n("Edit with:"), + QString(), 0 ) ); + int dlgrc = dlg->exec(); + if ( dlgrc && dlg ) { + offer = dlg->service(); + } + if ( !dlgrc || !offer ) + return false; + } + +#ifdef HAVE_SYS_INOTIFY_H + // monitor file + mInotifyFd = inotify_init(); + if ( mInotifyFd > 0 ) { + mInotifyWatch = inotify_add_watch( mInotifyFd, mUrl.path().toLatin1(), IN_CLOSE | IN_OPEN | IN_MODIFY ); + if ( mInotifyWatch >= 0 ) { + QSocketNotifier *sn = new QSocketNotifier( mInotifyFd, QSocketNotifier::Read, this ); + connect( sn, SIGNAL(activated(int)), SLOT(inotifyEvent()) ); + mHaveInotify = true; + mFileModified = false; + } + } else { + kWarning() <<"Failed to activate INOTIFY!"; + } +#endif + + // start the editor + QStringList params = KRun::processDesktopExec( *offer, list, false ); + mEditor = new KProcess( this ); + mEditor->setProgram( params ); + connect( mEditor, SIGNAL( finished( int, QProcess::ExitStatus ) ), + SLOT( editorExited() ) ); + mEditor->start(); + if ( !mEditor->waitForStarted() ) + return false; + mEditorRunning = true; + + mEditTime.start(); + return true; +} + +void EditorWatcher::inotifyEvent() +{ + assert( mHaveInotify ); +#ifdef HAVE_SYS_INOTIFY_H + int pending = -1; + char buffer[4096]; + ioctl( mInotifyFd, FIONREAD, &pending ); + while ( pending > 0 ) { + int size = read( mInotifyFd, buffer, qMin( pending, (int)sizeof(buffer) ) ); + pending -= size; + if ( size < 0 ) + break; // error + int offset = 0; + while ( size > 0 ) { + struct inotify_event *event = (struct inotify_event *) &buffer[offset]; + size -= sizeof( struct inotify_event ) + event->len; + offset += sizeof( struct inotify_event ) + event->len; + if ( event->mask & IN_OPEN ) + mFileOpen = true; + if ( event->mask & IN_CLOSE ) + mFileOpen = false; + if ( event->mask & IN_MODIFY ) + mFileModified = true; + } + } +#endif + mTimer.start( 500 ); + +} + +void EditorWatcher::editorExited() +{ + mEditorRunning = false; + mTimer.start( 500 ); +} + +void EditorWatcher::checkEditDone() +{ + if ( mEditorRunning || (mFileOpen && mHaveInotify) || mDone ) + return; + // protect us against double-deletion by calling this method again while + // the subeventloop of the message box is running + mDone = true; + // nobody can edit that fast, we seem to be unable to detect + // when the editor will be closed + if ( mEditTime.elapsed() <= 3000 ) { + KMessageBox::error( mParentWidget, + i18n( "KMail is unable to detect when the chosen editor is closed. " + "To avoid data loss, editing the attachment will be aborted." ), + i18n( "Unable to edit attachment" ) ); + } + + emit editDone( this ); + deleteLater(); +} +} +#include "editorwatcher.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/editorwatcher.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/editorwatcher.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/editorwatcher.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/editorwatcher.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,87 @@ +/* + Copyright (c) 2007 Volker Krause + + 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) any later version. + + 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. +*/ + +#ifndef MESSAGEVIEWER_EDITORWATCHER_H +#define MESSAGEVIEWER_EDITORWATCHER_H + +#include "messageviewer_export.h" +#include + +#include +#include +#include + +class KProcess; + +/** + Starts an editor for the given URL and emits an signal when + editing has been finished. Both, the editor process as well + as the edited file are watched to work with as many as possible + editors. +*/ +namespace MessageViewer { +class MESSAGEVIEWER_EXPORT EditorWatcher : public QObject +{ + Q_OBJECT + public: + + /** + * Constructs an EditorWatcher. + * @param parent the parent object of this EditorWatcher, which will take care of deleting + * this EditorWatcher if the parent is deleted. + * @param parentWidget the parent widget of this EditorWatcher, which will be used as the parent + * widget for message dialogs. + */ + EditorWatcher( const KUrl &url, const QString &mimeType, bool openWith, + QObject *parent, QWidget *parentWidget ); + + bool start(); + bool fileChanged() const { return mFileModified; } + KUrl url() { return mUrl;} + signals: + void editDone( EditorWatcher* watcher ); + + private slots: + void editorExited(); + void inotifyEvent(); + void checkEditDone(); + + private: + KUrl mUrl; + QString mMimeType; + bool mOpenWith; + KProcess *mEditor; + QWidget *mParentWidget; + + int mInotifyFd; + int mInotifyWatch; + bool mHaveInotify; + + bool mFileOpen; + bool mEditorRunning; + + bool mFileModified; + + QTimer mTimer; + QTime mEditTime; + + bool mError; + bool mDone; +}; +} +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/filehtmlwriter.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/filehtmlwriter.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/filehtmlwriter.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/filehtmlwriter.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,106 @@ +/* -*- c++ -*- + filehtmlwriter.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "filehtmlwriter.h" + +#include + +#include + + +namespace MessageViewer { + + FileHtmlWriter::FileHtmlWriter( const QString & filename ) + : HtmlWriter(), + mFile( filename.isEmpty() ? QString( "filehtmlwriter.out" ) : filename ) + { + mStream.setCodec( "UTF-8" ); + } + + FileHtmlWriter::~FileHtmlWriter() { + if ( mFile.isOpen() ) { + kWarning() <<"FileHtmlWriter: file still open!"; + mStream.setDevice(0); + mFile.close(); + } + } + + void FileHtmlWriter::begin( const QString & css ) { + openOrWarn(); + if ( !css.isEmpty() ) + write( "\n" ); + } + + void FileHtmlWriter::end() { + flush(); + mStream.setDevice(0); + mFile.close(); + } + + void FileHtmlWriter::reset() { + if ( mFile.isOpen() ) { + mStream.setDevice( 0 ); + mFile.close(); + } + } + + void FileHtmlWriter::write( const QString & str ) { + mStream << str; + flush(); + } + + void FileHtmlWriter::queue( const QString & str ) { + write( str ); + } + + void FileHtmlWriter::flush() { + mFile.flush(); + } + + void FileHtmlWriter::openOrWarn() { + if ( mFile.isOpen() ) { + kWarning() <<"FileHtmlWriter: file still open!"; + mStream.setDevice( 0 ); + mFile.close(); + } + if ( !mFile.open( QIODevice::WriteOnly ) ) + kWarning() <<"FileHtmlWriter: Cannot open file" << mFile.fileName(); + else + mStream.setDevice( &mFile ); + } + + void FileHtmlWriter::embedPart( const QByteArray & contentId, const QString & url ) { + mStream << "" << endl; + flush(); + } + + +} // namespace KMail diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/filehtmlwriter.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/filehtmlwriter.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/filehtmlwriter.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/filehtmlwriter.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,67 @@ +/* -*- c++ -*- + filehtmlwriter.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_FILEHTMLWRITER_H__ +#define __MESSAGEVIEWER_FILEHTMLWRITER_H__ + +#include "interfaces/htmlwriter.h" + +#include +#include + +class QString; + +namespace MessageViewer { + + class FileHtmlWriter : public MessageViewer::HtmlWriter { + public: + FileHtmlWriter( const QString & filename ); + virtual ~FileHtmlWriter(); + + void begin( const QString & cssDefs ); + void end(); + void reset(); + void write( const QString & str ); + void queue( const QString & str ); + void flush(); + void embedPart( const QByteArray & contentId, const QString & url ); + + private: + void openOrWarn(); + + private: + QFile mFile; + QTextStream mStream; + }; + +} // namespace MessageViewer + +#endif // __MESSAGEVIEWER_FILEHTMLWRITER_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/global.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/global.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/global.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/global.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,48 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#include "global.h" +Global * Global::mSelf = 0; + +Global * Global::instance() +{ + if ( !mSelf ) + mSelf = new Global(); + return mSelf; +} + +Global::Global() +{ + mSelf = this; + mConfig = 0; +} + +Global::~Global() +{ +} + +KSharedConfigPtr Global::config() +{ + if ( !mConfig ) + mConfig = KSharedConfig::openConfig( "mailviewerrc" ); + return mConfig; +} + + + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/global.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/global.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/global.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/global.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,48 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#ifndef MAILVIEWERGLOBAL_H +#define MAILVIEWERGLOBAL_H + +/** +Globally accesible methods and data structures. + + @author Andras Mantia +*/ + +#include + +class Global{ + +public: + static Global * instance(); + + ~Global(); + + void setConfig( KSharedConfigPtr config ) { mConfig = config; } + KSharedConfigPtr config(); + +private: + Global(); + + static Global * mSelf; + KSharedConfigPtr mConfig; +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/globalsettings_base.kcfgc /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/globalsettings_base.kcfgc --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/globalsettings_base.kcfgc 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/globalsettings_base.kcfgc 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,8 @@ +File=messageviewer.kcfg +ClassName=GlobalSettingsBase +Mutators=true +Singleton=true +ItemAccessors=true +SetUserTexts=true +IncludeFiles=qapplication.h + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/globalsettings.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/globalsettings.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/globalsettings.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/globalsettings.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,62 @@ +/* + This file is part of KMail. + + Copyright (c) 2005 David Faure + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2, + as published by the Free Software Foundation. + + 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. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + + +#include "globalsettings.h" +#include + +GlobalSettings *GlobalSettings::mSelf = 0; + +GlobalSettings *GlobalSettings::self() +{ + if ( !mSelf ) { + mSelf = new GlobalSettings(); + mSelf->readConfig(); + } + + return mSelf; +} + +GlobalSettings::GlobalSettings() +{ + mConfigSyncTimer = new QTimer( this ); + mConfigSyncTimer->setSingleShot( true ); + connect( mConfigSyncTimer, SIGNAL( timeout() ), this, SLOT( slotSyncNow() ) ); +} + +void GlobalSettings::requestSync() +{ + if ( !mConfigSyncTimer->isActive() ) + mConfigSyncTimer->start( 0 ); +} + +void GlobalSettings::slotSyncNow() +{ + config()->sync(); +} + +GlobalSettings::~GlobalSettings() +{ +} + +#include "globalsettings.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/globalsettings.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/globalsettings.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/globalsettings.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/globalsettings.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,56 @@ +/* + This file is part of KMail. + + Copyright (c) 2005 David Faure + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2, + as published by the Free Software Foundation. + + 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. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef MESSAGEVIEWER_GLOBALSETTINGS_H +#define MESSAGEVIEWER_GLOBALSETTINGS_H + +#include "globalsettings_base.h" +#include "messageviewer_export.h" +class QTimer; + +class MESSAGEVIEWER_EXPORT GlobalSettings : public GlobalSettingsBase +{ + Q_OBJECT +public: + static GlobalSettings *self(); + + /** Call this slot instead of directly @ref KConfig::sync() to + minimize the overall config writes. Calling this slot will + schedule a sync of the application config file using a timer, so + that many consecutive calls can be condensed into a single + sync, which is more efficient. */ + void requestSync(); + +private slots: + void slotSyncNow(); + +private: + GlobalSettings(); + virtual ~GlobalSettings(); + static GlobalSettings *mSelf; + + QTimer *mConfigSyncTimer; + +}; + +#endif /* KMAIL_GLOBALSETTINGS_H */ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/headerstrategy.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/headerstrategy.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/headerstrategy.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/headerstrategy.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,306 @@ +/* -*- c++ -*- + headerstrategy.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + + +#include "headerstrategy.h" +#include "global.h" + +#include +#include +#include + +// +// Header tables: +// +namespace MessageViewer { +static const char * briefHeaders[] = { + "subject", "from", "cc", "bcc", "date" +}; +static const int numBriefHeaders = sizeof briefHeaders / sizeof *briefHeaders; + + +static const char * standardHeaders[] = { + "subject", "from", "cc", "bcc", "to" +}; +static const int numStandardHeaders = sizeof standardHeaders / sizeof *standardHeaders; + + +static const char * richHeaders[] = { + "subject", "date", "from", "cc", "bcc", "to", + "organization", "organisation", "reply-to", + "user-agent", "x-mailer" +}; +static const int numRichHeaders = sizeof richHeaders / sizeof *richHeaders; + +// +// Convenience function +// + +static QStringList stringList( const char * headers[], int numHeaders ) { + QStringList sl; + for ( int i = 0 ; i < numHeaders ; ++i ) + sl.push_back( headers[i] ); + return sl; +} + +// +// AllHeaderStrategy: +// show everything +// + +class AllHeaderStrategy : public HeaderStrategy { + friend class MessageViewer::HeaderStrategy; +protected: + AllHeaderStrategy() : HeaderStrategy() {} + virtual ~AllHeaderStrategy() {} + +public: + const char * name() const { return "all"; } + const HeaderStrategy * next() const { return rich(); } + const HeaderStrategy * prev() const { return custom(); } + + DefaultPolicy defaultPolicy() const { return Display; } + + bool showHeader( const QString & ) const { + return true; // more efficient than default impl + } +}; + +// +// RichHeaderStrategy: +// Date, Subject, From, To, CC, ### what exactly? +// + +class RichHeaderStrategy : public HeaderStrategy { + friend class MessageViewer::HeaderStrategy; +protected: + RichHeaderStrategy() + : HeaderStrategy(), +mHeadersToDisplay( stringList( richHeaders, numRichHeaders ) ) {} + virtual ~RichHeaderStrategy() {} + +public: + const char * name() const { return "rich"; } + const HeaderStrategy * next() const { return standard(); } + const HeaderStrategy * prev() const { return all(); } + + QStringList headersToDisplay() const { return mHeadersToDisplay; } + DefaultPolicy defaultPolicy() const { return Hide; } + +private: + const QStringList mHeadersToDisplay; +}; + +// +// StandardHeaderStrategy: +// BCC, CC, Date, From, Subject, To +// + +class StandardHeaderStrategy : public HeaderStrategy { + friend class MessageViewer::HeaderStrategy; +protected: + StandardHeaderStrategy() + : HeaderStrategy(), +mHeadersToDisplay( stringList( standardHeaders, numStandardHeaders) ) {} + virtual ~StandardHeaderStrategy() {} + +public: + const char * name() const { return "standard"; } + const HeaderStrategy * next() const { return brief(); } + const HeaderStrategy * prev() const { return rich(); } + + QStringList headersToDisplay() const { return mHeadersToDisplay; } + DefaultPolicy defaultPolicy() const { return Hide; } + +private: + const QStringList mHeadersToDisplay; +}; + +// +// BriefHeaderStrategy +// From, Subject, Date +// + +class BriefHeaderStrategy : public HeaderStrategy { + friend class MessageViewer::HeaderStrategy; +protected: + BriefHeaderStrategy() + : HeaderStrategy(), +mHeadersToDisplay( stringList( briefHeaders, numBriefHeaders ) ) {} + virtual ~BriefHeaderStrategy() {} + +public: + const char * name() const { return "brief"; } + const HeaderStrategy * next() const { return custom(); } + const HeaderStrategy * prev() const { return standard(); } + + QStringList headersToDisplay() const { return mHeadersToDisplay; } + DefaultPolicy defaultPolicy() const { return Hide; } + +private: + const QStringList mHeadersToDisplay; +}; + + +// +// CustomHeaderStrategy +// Determined by user +// + +class CustomHeaderStrategy : public HeaderStrategy { + friend class MessageViewer::HeaderStrategy; +protected: + CustomHeaderStrategy(); + virtual ~CustomHeaderStrategy() {} + +public: + const char * name() const { return "custom"; } + const HeaderStrategy * next() const { return all(); } + const HeaderStrategy * prev() const { return brief(); } + + QStringList headersToDisplay() const { return mHeadersToDisplay; } + QStringList headersToHide() const { return mHeadersToHide; } + DefaultPolicy defaultPolicy() const { return mDefaultPolicy; } + +private: + QStringList mHeadersToDisplay; + QStringList mHeadersToHide; + DefaultPolicy mDefaultPolicy; +}; + + +CustomHeaderStrategy::CustomHeaderStrategy() + : HeaderStrategy() +{ + KConfigGroup customHeader( Global::instance()->config(), "Custom Headers" ); + if ( customHeader.hasKey( "headers to display" ) ) { + mHeadersToDisplay = customHeader.readEntry( "headers to display", QStringList() ); + for ( QStringList::iterator it = mHeadersToDisplay.begin() ; it != mHeadersToDisplay.end() ; ++ it ) +*it = (*it).toLower(); + } else + mHeadersToDisplay = stringList( standardHeaders, numStandardHeaders ); + + if ( customHeader.hasKey( "headers to hide" ) ) { + mHeadersToHide = customHeader.readEntry( "headers to hide", QStringList() ); + for ( QStringList::iterator it = mHeadersToHide.begin() ; it != mHeadersToHide.end() ; ++ it ) +*it = (*it).toLower(); + } + + mDefaultPolicy = customHeader.readEntry( "default policy", "hide" ) == "display" ? Display : Hide ; +} + +// +// HeaderStrategy abstract base: +// + +HeaderStrategy::HeaderStrategy() { + +} + +HeaderStrategy::~HeaderStrategy() { + +} + +QStringList HeaderStrategy::headersToDisplay() const { + return QStringList(); +} + +QStringList HeaderStrategy::headersToHide() const { + return QStringList(); +} + +bool HeaderStrategy::showHeader( const QString & header ) const { + if ( headersToDisplay().contains( header.toLower() ) ) return true; + if ( headersToHide().contains( header.toLower() ) ) return false; + return defaultPolicy() == Display; +} + +const HeaderStrategy * HeaderStrategy::create( Type type ) { + switch ( type ) { + case All: return all(); + case Rich: return rich(); + case Standard: return standard(); + case Brief: return brief(); + case Custom: return custom(); + } + kFatal( 5006 ) <<"HeaderStrategy::create(): Unknown header strategy ( type ==" + << (int)type << ") requested!"; + return 0; // make compiler happy +} + +const HeaderStrategy * HeaderStrategy::create( const QString & type ) { + QString lowerType = type.toLower(); + if ( lowerType == "all" ) return all(); + if ( lowerType == "rich" ) return HeaderStrategy::rich(); + //if ( lowerType == "standard" ) return standard(); // not needed, see below + if ( lowerType == "brief" ) return brief(); + if ( lowerType == "custom" ) return custom(); + // don't kFatal here, b/c the strings are user-provided + // (KConfig), so fail gracefully to the default: + return standard(); +} + +static const HeaderStrategy * allStrategy = 0; +static const HeaderStrategy * richStrategy = 0; +static const HeaderStrategy * standardStrategy = 0; +static const HeaderStrategy * briefStrategy = 0; +static const HeaderStrategy * customStrategy = 0; + +const HeaderStrategy * HeaderStrategy::all() { + if ( !allStrategy ) + allStrategy = new AllHeaderStrategy(); + return allStrategy; +} + +const HeaderStrategy * HeaderStrategy::rich() { + if ( !richStrategy ) + richStrategy = new RichHeaderStrategy(); + return richStrategy; +} + +const HeaderStrategy * HeaderStrategy::standard() { + if ( !standardStrategy ) + standardStrategy = new StandardHeaderStrategy(); + return standardStrategy; +} + +const HeaderStrategy * HeaderStrategy::brief() { + if ( !briefStrategy ) + briefStrategy = new BriefHeaderStrategy(); + return briefStrategy; +} + +const HeaderStrategy * HeaderStrategy::custom() { + if ( !customStrategy ) + customStrategy = new CustomHeaderStrategy(); + return customStrategy; +} +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/headerstrategy.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/headerstrategy.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/headerstrategy.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/headerstrategy.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,79 @@ +/* -*- c++ -*- + headerstrategy.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_HEADERSTRATEGY_H__ +#define __MESSAGEVIEWER_HEADERSTRATEGY_H__ + +#include "messageviewer_export.h" + +class QString; +class QStringList; +namespace MessageViewer { +class MESSAGEVIEWER_EXPORT HeaderStrategy { +protected: + HeaderStrategy(); + virtual ~HeaderStrategy(); + +public: + // + // Factory methods: + // + enum Type { All, Rich, Standard, Brief, Custom }; + + static const HeaderStrategy * create( Type type ); + static const HeaderStrategy * create( const QString & type ); + + static const HeaderStrategy * all(); + static const HeaderStrategy * rich(); + static const HeaderStrategy * standard(); + static const HeaderStrategy * brief(); + static const HeaderStrategy * custom(); + + // + // Methods for handling the strategies: + // + virtual const char * name() const = 0; + virtual const HeaderStrategy * next() const = 0; + virtual const HeaderStrategy * prev() const = 0; + + // + // HeaderStrategy interface: + // + enum DefaultPolicy { Display, Hide }; + + virtual QStringList headersToDisplay() const; + virtual QStringList headersToHide() const; + virtual DefaultPolicy defaultPolicy() const = 0; + virtual bool showHeader( const QString & header ) const; +}; + +} +#endif // __MESSAGEVIEWER_HEADERSTRATEGY_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/headerstyle.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/headerstyle.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/headerstyle.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/headerstyle.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,982 @@ +/* -*- c++ -*- + headerstyle.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "headerstyle.h" + +#include "headerstrategy.h" +#include +using KPIMUtils::LinkLocator; +#include "spamheaderanalyzer.h" +#include "globalsettings.h" +#include "stringutil.h" +#include "nodehelper.h" +#include "global.h" + +#include +#include "libkdepim/kxface.h" +using namespace KPIM; + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +// +// Convenience functions: +// +static inline QString directionOf( const QString & str ) { + return str.isRightToLeft() ? "rtl" : "ltr" ; +} + +// ### tmp wrapper to make kmreaderwin code working: +static QString strToHtml( const QString & str, + int flags = LinkLocator::PreserveSpaces ) { + return LinkLocator::convertToHtml( str, flags ); +} + +// +// BriefHeaderStyle +// Show everything in a single line, don't show header field names. +// +namespace MessageViewer { +class BriefHeaderStyle : public HeaderStyle { + friend class MessageViewer::HeaderStyle; +protected: + BriefHeaderStyle() : HeaderStyle() {} + virtual ~BriefHeaderStyle() {} + +public: + const char * name() const { return "brief"; } + const HeaderStyle * next() const { return plain(); } + const HeaderStyle * prev() const { return fancy(); } + + QString format( KMime::Message * message, const HeaderStrategy * strategy, + const QString & vCardName, bool printing, bool topLevel ) const; +}; + +QString BriefHeaderStyle::format( KMime::Message * message, + const HeaderStrategy * strategy, + const QString & vCardName, bool printing, bool topLevel ) const { + Q_UNUSED( topLevel ); + if ( !message ) return QString(); + if ( !strategy ) + strategy = HeaderStrategy::brief(); + + // The direction of the header is determined according to the direction + // of the application layout. + + QString dir = QApplication::isRightToLeft() ? "rtl" : "ltr" ; + + // However, the direction of the message subject within the header is + // determined according to the contents of the subject itself. Since + // the "Re:" and "Fwd:" prefixes would always cause the subject to be + // considered left-to-right, they are ignored when determining its + // direction. + + QString subjectDir; + if ( message->subject(false) ) + subjectDir = directionOf( NodeHelper::instance()->cleanSubject( message ) ); + else + subjectDir = directionOf( i18n("No Subject") ); + + // Prepare the date string (when printing always use the localized date) + QString dateString; + if( printing ) { + KDateTime dateTime = message->date()->dateTime(); + KLocale * locale = KGlobal::locale(); + dateString = locale->formatDateTime( dateTime ); + } else { + dateString = dateStr( message->date()->dateTime() ); + } + + QString headerStr = "
\n"; + + if ( strategy->showHeader( "subject" ) ) + headerStr += "
\n" + "" + + strToHtml( message->subject()->asUnicodeString() ) + + "
\n"; + + QStringList headerParts; + + if ( strategy->showHeader( "from" ) ) { + QString fromStr = message->from()->asUnicodeString(); +/*TODO(Andras) review if it can happen or not + if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name + fromStr = message->fromStrip(); // let's use that +*/ + QString fromPart = StringUtil::emailAddrAsAnchor( fromStr, true ); + if ( !vCardName.isEmpty() ) + fromPart += "  " + i18n("[vCard]") + ""; + headerParts << fromPart; + } + + if ( strategy->showHeader( "cc" ) && message->cc(false) ) + headerParts << i18n("CC: ") + StringUtil::emailAddrAsAnchor( message->cc()->asUnicodeString(), true ); + + if ( strategy->showHeader( "bcc" ) && message->bcc(false) ) + headerParts << i18n("BCC: ") + StringUtil::emailAddrAsAnchor( message->bcc()->asUnicodeString(), true ); + + if ( strategy->showHeader( "date" ) ) + headerParts << strToHtml(dateShortStr(message->date()->dateTime())); + + // remove all empty (modulo whitespace) entries and joins them via ", \n" + headerStr += " (" + headerParts.filter( QRegExp( "\\S" ) ).join( ",\n" ) + ')'; + + headerStr += "
\n"; + + // ### iterate over the rest of strategy->headerToDisplay() (or + // ### all headers if DefaultPolicy == Display) (elsewhere, too) + return headerStr; +} + +// +// PlainHeaderStyle: +// show every header field on a line by itself, +// show subject larger +// + +class PlainHeaderStyle : public HeaderStyle { + friend class MessageViewer::HeaderStyle; +protected: + PlainHeaderStyle() : HeaderStyle() {} + virtual ~PlainHeaderStyle() {} + +public: + const char * name() const { return "plain"; } + const HeaderStyle * next() const { return fancy(); } + const HeaderStyle * prev() const { return brief(); } + + QString format( KMime::Message * message, const HeaderStrategy * strategy, + const QString & vCardName, bool printing, bool topLevel ) const; + +private: + QString formatAllMessageHeaders( KMime::Message * message ) const; +}; + +QString PlainHeaderStyle::format( KMime::Message * message, + const HeaderStrategy * strategy, + const QString & vCardName, bool printing, bool topLevel ) const { + Q_UNUSED( topLevel ); + if ( !message ) return QString(); + if ( !strategy ) + strategy = HeaderStrategy::rich(); + + // The direction of the header is determined according to the direction + // of the application layout. + + QString dir = ( QApplication::isRightToLeft() ? "rtl" : "ltr" ); + + // However, the direction of the message subject within the header is + // determined according to the contents of the subject itself. Since + // the "Re:" and "Fwd:" prefixes would always cause the subject to be + // considered left-to-right, they are ignored when determining its + // direction. + + QString subjectDir; + if (message->subject(false)) + subjectDir = directionOf( NodeHelper::instance()->cleanSubject( message ) ); + else + subjectDir = directionOf( i18n("No Subject") ); + + // Prepare the date string (when printing always use the localized date) + QString dateString; + if( printing ) { + KDateTime dateTime = message->date()->dateTime(); + KLocale* locale = KGlobal::locale(); + dateString = locale->formatDateTime( dateTime ); + } + else { + dateString = dateStr(message->date()->dateTime()); + } + + QString headerStr; + + if ( strategy->headersToDisplay().isEmpty() + && strategy->defaultPolicy() == HeaderStrategy::Display ) { + // crude way to emulate "all" headers - Note: no strings have + // i18n(), so direction should always be ltr. + headerStr= QString("
"); + headerStr += formatAllMessageHeaders( message ); + return headerStr + "
"; + } + + headerStr = QString("
").arg(dir); + + //case HdrLong: + if ( strategy->showHeader( "subject" ) ) + headerStr += QString("
" + + strToHtml(message->subject()->asUnicodeString()) + "
\n") + .arg(subjectDir); + + if ( strategy->showHeader( "date" ) ) + headerStr.append(i18n("Date: ") + strToHtml(dateString)+"
\n"); + + if ( strategy->showHeader( "from" ) ) { + QString fromStr = message->from()->asUnicodeString(); +/*FIXME(Andras) review if it is still needed + if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name + fromStr = message->fromStrip(); // let's use that +*/ + headerStr.append( i18n("From: ") + + StringUtil::emailAddrAsAnchor( fromStr, false, "", true ) ); + if ( !vCardName.isEmpty() ) + headerStr.append("  " + i18n("[vCard]") + "" ); + + if ( strategy->showHeader( "organization" ) + && message->headerByType("Organization")) + headerStr.append("  (" + + strToHtml(message->headerByType("Organization")->asUnicodeString()) + ')'); + headerStr.append("
\n"); + } + + if ( strategy->showHeader( "to" ) ) + headerStr.append(i18nc("To-field of the mailheader.", "To: ")+ + StringUtil::emailAddrAsAnchor(message->to()->asUnicodeString(),false) + "
\n"); + + if ( strategy->showHeader( "cc" ) && message->cc(false) ) + headerStr.append(i18n("CC: ")+ + StringUtil::emailAddrAsAnchor(message->cc()->asUnicodeString(),false) + "
\n"); + + if ( strategy->showHeader( "bcc" ) && message->bcc(false) ) + headerStr.append(i18n("BCC: ")+ + StringUtil::emailAddrAsAnchor(message->bcc()->asUnicodeString(),false) + "
\n"); + + if ( strategy->showHeader( "reply-to" ) && message->replyTo(false)) + headerStr.append(i18n("Reply to: ")+ + StringUtil::emailAddrAsAnchor(message->replyTo()->asUnicodeString(),false) + "
\n"); + + headerStr += "
\n"; + + return headerStr; +} + +QString PlainHeaderStyle::formatAllMessageHeaders( KMime::Message * message ) const { + QByteArray head = message->head(); + KMime::Headers::Generic *header = message->nextHeader(head); + QString result; + while ( header ) { + result += QLatin1String(header->type()) + ": "; + result += strToHtml( header->asUnicodeString() ); + delete header; + header = message->nextHeader(head); + } + + return result; +} + +// +// FancyHeaderStyle: +// Like PlainHeaderStyle, but with slick frames and background colours. +// + +class FancyHeaderStyle : public HeaderStyle { + friend class MessageViewer::HeaderStyle; +protected: + FancyHeaderStyle() : HeaderStyle() {} + virtual ~FancyHeaderStyle() {} + +public: + const char * name() const { return "fancy"; } + const HeaderStyle * next() const { return enterprise(); } + const HeaderStyle * prev() const { return plain(); } + + QString format( KMime::Message * message, const HeaderStrategy * strategy, + const QString & vCardName, bool printing, bool topLevel ) const; + static QString imgToDataUrl( const QImage & image ); + +private: + static QString drawSpamMeter( SpamError spamError, double percent, double confidence, + const QString & filterHeader, const QString & confidenceHeader ); + +}; + +QString FancyHeaderStyle::drawSpamMeter( SpamError spamError, double percent, double confidence, + const QString & filterHeader, const QString & confidenceHeader ) +{ + static const int meterWidth = 20; + static const int meterHeight = 5; + QImage meterBar( meterWidth, 1, QImage::Format_Indexed8/*QImage::Format_RGB32*/ ); + meterBar.setNumColors( 24 ); + + const unsigned short gradient[meterWidth][3] = { + { 0, 255, 0 }, + { 27, 254, 0 }, + { 54, 252, 0 }, + { 80, 250, 0 }, + { 107, 249, 0 }, + { 135, 247, 0 }, + { 161, 246, 0 }, + { 187, 244, 0 }, + { 214, 242, 0 }, + { 241, 241, 0 }, + { 255, 228, 0 }, + { 255, 202, 0 }, + { 255, 177, 0 }, + { 255, 151, 0 }, + { 255, 126, 0 }, + { 255, 101, 0 }, + { 255, 76, 0 }, + { 255, 51, 0 }, + { 255, 25, 0 }, + { 255, 0, 0 } + }; + meterBar.setColor( meterWidth + 1, qRgb( 255, 255, 255 ) ); + meterBar.setColor( meterWidth + 2, qRgb( 170, 170, 170 ) ); + if ( spamError != noError ) // grey is for errors + meterBar.fill( meterWidth + 2 ); + else { + meterBar.fill( meterWidth + 1 ); + int max = qMin( meterWidth, static_cast( percent ) / 5 ); + for ( int i = 0; i < max; ++i ) { + meterBar.setColor( i+1, qRgb( gradient[i][0], gradient[i][1], + gradient[i][2] ) ); + meterBar.setPixel( i, 0, i+1 ); + } + } + + QString titleText; + QString confidenceString = QString(); + if ( spamError == noError ) + { + if ( confidence >= 0 ) + { + confidenceString = QString::number( confidence ) + "%  "; + titleText = i18n("%1% probability of being spam with confidence %3%.\n\n" + "Full report:\nProbability=%2\nConfidence=%4", + percent, filterHeader, confidence, confidenceHeader ); + } + else // do not show negative confidence + { + titleText = i18n("%1% probability of being spam.\n\n" + "Full report:\nProbability=%2", + percent, filterHeader); + } + } + else + { + QString errorMsg; + switch ( spamError ) + { + case errorExtractingAgentString: + errorMsg = i18n( "No Spam agent" ); + break; + case couldNotConverScoreToFloat: + errorMsg = i18n( "Spam filter score not a number" ); + break; + case couldNotConvertThresholdToFloatOrThresholdIsNegative: + errorMsg = i18n( "Threshold not a valid number" ); + break; + case couldNotFindTheScoreField: + errorMsg = i18n( "Spam filter score could not be extracted from header" ); + break; + case couldNotFindTheThresholdField: + errorMsg = i18n( "Threshold could not be extracted from header" ); + break; + default: + errorMsg = i18n( "Error evaluating spam score" ); + break; + } + // report the error in the spam filter + titleText = i18n("%1.\n\n" + "Full report:\n%2", + errorMsg, filterHeader ); + } + return QString("  ") + .arg( imgToDataUrl( meterBar ), QString::number( meterWidth ), + QString::number( meterHeight ), titleText ) + confidenceString; +} + + +QString FancyHeaderStyle::format( KMime::Message * message, + const HeaderStrategy * strategy, + const QString & vCardName, bool printing, bool topLevel ) const { + Q_UNUSED( topLevel ); + if ( !message ) return QString(); + if ( !strategy ) + strategy = HeaderStrategy::rich(); + + KConfigGroup configReader( Global::instance()->config(), "Reader" ); + + // ### from kmreaderwin begin + // The direction of the header is determined according to the direction + // of the application layout. + + QString dir = ( QApplication::isRightToLeft() ? "rtl" : "ltr" ); + QString headerStr = QString("
\n").arg(dir); + + // However, the direction of the message subject within the header is + // determined according to the contents of the subject itself. Since + // the "Re:" and "Fwd:" prefixes would always cause the subject to be + // considered left-to-right, they are ignored when determining its + // direction. + + QString subjectDir; + if ( message->subject(false) ) + subjectDir = directionOf( NodeHelper::instance()->cleanSubject( message ) ); + else + subjectDir = directionOf( i18n("No Subject") ); + + // Prepare the date string (when printing always use the localized date) + QString dateString; + if( printing ) { + KDateTime dateTime = message->date()->dateTime(); + KLocale* locale = KGlobal::locale(); + dateString = locale->formatDateTime( dateTime ); + } + else { + dateString = dateStr(message->date()->dateTime()); + } + + // Spam header display. + // If the spamSpamStatus config value is true then we look for headers + // from a few spam filters and try to create visually meaningful graphics + // out of the spam scores. + + QString spamHTML; + + if ( GlobalSettings::self()->showSpamStatus() ) { + SpamScores scores = SpamHeaderAnalyzer::getSpamScores( message ); + for ( SpamScoresIterator it = scores.begin(); it != scores.end(); ++it ) + spamHTML += (*it).agent() + ' ' + + drawSpamMeter( (*it).error(), (*it).score(), (*it).confidence(), (*it).spamHeader(), (*it).confidenceHeader() ); + } + + QString userHTML; + + KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true ); + KABC::Addressee::List addresses = addressBook->findByEmail( KPIMUtils::firstEmailAddress( message->from()->asUnicodeString() ) ); + + QString photoURL; + int photoWidth = 60; + int photoHeight = 60; + if( addresses.count() == 1 ) + { + // picture + if ( addresses[0].photo().isIntern() ) + { + // get photo data and convert to data: url + //kDebug() <<"INTERNAL photo found"; + QImage photo = addresses[0].photo().data(); + if ( !photo.isNull() ) + { + photoWidth = photo.width(); + photoHeight = photo.height(); + // scale below 60, otherwise it can get way too large + if ( photoHeight > 60 ) { + double ratio = ( double )photoHeight / ( double )photoWidth; + photoHeight = 60; + photoWidth = (int)( 60 / ratio ); + photo = photo.scaled( photoWidth, photoHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + } + photoURL = imgToDataUrl( photo ); + } + } + else + { + //kDebug() <<"URL found"; + photoURL = addresses[0].photo().url(); + if ( photoURL.startsWith('/') ) + photoURL.prepend( "file:" ); + } + } + else // TODO: find a usable one + { + userHTML = " "; + } + + if( photoURL.isEmpty() && message->headerByType( "Face" )) { + // no photo, look for a Face header + QString faceheader = message->headerByType( "Face" )->asUnicodeString(); + if ( !faceheader.isEmpty() ) { + QImage faceimage; + + kDebug() <<"Found Face: header"; + + QByteArray facestring = faceheader.toUtf8(); + // Spec says header should be less than 998 bytes + // Face: is 5 characters + if ( facestring.length() < 993 ) { + QByteArray facearray = QByteArray::fromBase64( facestring ); + + QImage faceimage; + if ( faceimage.loadFromData( facearray, "png" ) ) { + // Spec says image must be 48x48 pixels + if ( ( 48 == faceimage.width() ) && ( 48 == faceimage.height() ) ) { + photoURL = imgToDataUrl( faceimage ); + photoWidth = 48; + photoHeight = 48; + } else { + kDebug() <<"Face: header image is" << faceimage.width() <<"by" << faceimage.height() <<"not 48x48 Pixels"; + } + } else { + kDebug() <<"Failed to load decoded png from Face: header"; + } + } else { + kDebug() <<"Face: header too long at" << facestring.length(); + } + } + } + + if( photoURL.isEmpty() && message->headerByType( "X-Face" )) + { + // no photo, look for a X-Face header + QString xfaceURL; + QString xfhead = message->headerByType( "X-Face" )->asUnicodeString(); + if ( !xfhead.isEmpty() ) + { + KXFace xf; + photoURL = imgToDataUrl( xf.toImage( xfhead ) ); + photoWidth = 48; + photoHeight = 48; + + } + } + + if( !photoURL.isEmpty() ) + { + //kDebug() <<"Got a photo:" << photoURL; + userHTML = QString("") + .arg( photoURL ).arg( photoWidth ).arg( photoHeight ); + userHTML = QString("
") + userHTML + "
"; + } + + //case HdrFancy: + // the subject line and box below for details + if ( strategy->showHeader( "subject" ) ) { + const int flags = LinkLocator::PreserveSpaces | + ( GlobalSettings::self()->showEmoticons() ? + LinkLocator::ReplaceSmileys : 0 ); + + headerStr += QString("
%2
\n") + .arg(subjectDir) + .arg(!message->subject(false)? + i18n("No Subject") : + strToHtml( message->subject()->asUnicodeString(), flags )); + } + headerStr += "
\n"; + //headerStr += "
\n"; + // from line + // the mailto: URLs can contain %3 etc., therefore usage of multiple + // QString::arg is not possible + if ( strategy->showHeader( "from" ) ) { + QString fromStr = message->from()->asUnicodeString(); + /*TODO(Andras) review if needed + if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name + fromStr = message->fromStrip(); // let's use that + */ + headerStr += QString("\n" + "\n"; + } + // to line + if ( strategy->showHeader( "to" ) ) + headerStr.append(QString("\n" + "\n") + .arg(i18nc("To-field of the mail header.","To: ")) + .arg(StringUtil::emailAddrAsAnchor(message->to()->asUnicodeString(),false))); + + // cc line, if any + if ( strategy->showHeader( "cc" ) && message->cc(false)) + headerStr.append(QString("\n" + "\n") + .arg(i18n("CC: ")) + .arg(StringUtil::emailAddrAsAnchor(message->cc()->asUnicodeString(),false))); + + // Bcc line, if any + if ( strategy->showHeader( "bcc" ) && message->bcc(false)) + headerStr.append(QString("\n" + "\n") + .arg(i18n("BCC: ")) + .arg(StringUtil::emailAddrAsAnchor(message->bcc()->asUnicodeString(),false))); + + if ( strategy->showHeader( "date" ) ) + headerStr.append(QString("\n" + "\n") + .arg(i18n("Date: ")) + .arg( directionOf( dateStr(message->date()->dateTime() ) ) ) + .arg(strToHtml(dateString))); + if ( GlobalSettings::self()->showUserAgent() ) { + if ( strategy->showHeader( "user-agent" ) ) { + if ( message->headerByType("User-Agent") ) { + headerStr.append(QString("\n" + "\n") + .arg(i18n("User-Agent: ")) + .arg( strToHtml( message->headerByType("User-Agent")->as7BitString() ) ) ); + } + } + + if ( strategy->showHeader( "x-mailer" ) ) { + if ( message->headerByType("X-Mailer") ) { + headerStr.append(QString("\n" + "\n") + .arg(i18n("X-Mailer: ")) + .arg( strToHtml( message->headerByType("X-Mailer")->as7BitString() ) ) ); + } + } + } + headerStr.append( QString( "" ) ); + headerStr.append( + QString( "
%1") + .arg(i18n("From: ")) + + StringUtil::emailAddrAsAnchor( fromStr, false ) + + ( message->headerByType( "Resent-From" ) ? " " + + i18n("(resent from %1)", + StringUtil::emailAddrAsAnchor( + message->headerByType( "Resent-From" )->asUnicodeString(),false) ) + : QString("") ) + + ( !vCardName.isEmpty() ? "  " + + i18n("[vCard]") + "" + : QString("") ) + + ( !message->headerByType("Organization") + ? QString("") + : "  (" + + strToHtml(message->headerByType("Organization")->asUnicodeString()) + + ')') + + "
%1%2
%1%2
%1%2
%1%3
%1%2
%1%2
%1
\n" ).arg(userHTML) ); + + if ( !spamHTML.isEmpty() ) + headerStr.append( QString( "
%2 %3
\n") + .arg( subjectDir, i18n("Spam Status:"), spamHTML ) ); + + headerStr += "
\n\n"; + return headerStr; +} + +QString FancyHeaderStyle::imgToDataUrl( const QImage &image ) +{ + QByteArray ba; + QBuffer buffer( &ba ); + buffer.open( QIODevice::WriteOnly ); + image.save( &buffer, "PNG" ); + return QString::fromLatin1("data:image/%1;base64,%2") + .arg( QString::fromLatin1( "PNG" ), QString::fromLatin1( ba.toBase64() ) ); +} + +// ##################### + +class EnterpriseHeaderStyle : public HeaderStyle { + friend class MessageViewer::HeaderStyle; +protected: + EnterpriseHeaderStyle() : HeaderStyle() {} + virtual ~EnterpriseHeaderStyle() {} + +public: + const char * name() const { return "enterprise"; } + const HeaderStyle * next() const { return brief(); } + const HeaderStyle * prev() const { return fancy(); } + + QString format( KMime::Message * message, const HeaderStrategy * strategy, + const QString & vCardName, bool printing, bool topLevel ) const; +}; + +QString EnterpriseHeaderStyle::format( KMime::Message * message, + const HeaderStrategy * strategy, + const QString & vCardName, bool printing, bool topLevel ) const +{ + if ( !message ) return QString(); + if ( !strategy ) { + strategy = HeaderStrategy::brief(); + } + + // The direction of the header is determined according to the direction + // of the application layout. + + QString dir = ( QApplication::layoutDirection() == Qt::RightToLeft ) ? + "rtl" : "ltr" ; + + // However, the direction of the message subject within the header is + // determined according to the contents of the subject itself. Since + // the "Re:" and "Fwd:" prefixes would always cause the subject to be + // considered left-to-right, they are ignored when determining its + // direction. + +//TODO(Andras) this is duplicate code, try to factor out! + QString subjectDir; + if (message->subject(false)) + subjectDir = directionOf( NodeHelper::instance()->cleanSubject( message ) ); + else + subjectDir = directionOf( i18n("No Subject") ); + + // colors depend on if it is encapsulated or not + QColor fontColor( Qt::white ); + QString linkColor = "class =\"white\""; + const QColor activeColor = KColorScheme( QPalette::Active, KColorScheme::Selection ). + background().color(); + QColor activeColorDark = activeColor.dark(130); + // reverse colors for encapsulated + if( !topLevel ){ + activeColorDark = activeColor.dark(50); + fontColor = QColor(Qt::black); + linkColor = "class =\"black\""; + } + +//TODO(Andras) this looks like duplicate code, try to factor out! + QStringList headerParts; + if ( strategy->showHeader( "to" ) ) { + headerParts << StringUtil::emailAddrAsAnchor( message->to()->asUnicodeString(), false, linkColor ); + } + + if ( strategy->showHeader( "cc" ) && message->cc(false) ) { + headerParts << StringUtil::emailAddrAsAnchor( message->cc()->asUnicodeString(), true, linkColor ); + } + + if ( strategy->showHeader( "bcc" ) && message->bcc(false) ) { + headerParts << StringUtil::emailAddrAsAnchor( message->bcc()->asUnicodeString(), true, linkColor ); + } + + // remove all empty (modulo whitespace) entries and joins them via ", \n" + QString headerPart = ' ' + headerParts.filter( QRegExp( "\\S" ) ).join( ", " ); + +//TODO(Andras) this is duplicate code, try to factor out! + // Prepare the date string (when printing always use the localized date) + QString dateString; + if( printing ) { + KDateTime dateTime = message->date()->dateTime(); + KLocale* locale = KGlobal::locale(); + dateString = locale->formatDateTime( dateTime ); + } + else { + dateString = dateStr(message->date()->dateTime()); + } + + QString imgpath( KStandardDirs::locate("data","kmail/pics/") ); + imgpath.append("enterprise_"); + const QString borderSettings( " padding-top: 0px; padding-bottom: 0px; border-width: 0px " ); + QString headerStr; + + // 3D borders + if(topLevel) + headerStr += + "
 
" + "
 
"; + + headerStr += + "
"+dateString+"
" + // #0057ae + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n"; + + // subject + //strToHtml( message->subject() ) + if ( strategy->showHeader( "subject" ) ) { + headerStr += + " \n" + " \n" + " \n" + " \n"; + } + + // from + if ( strategy->showHeader( "from" ) ) { + QString fromStr = message->from()->asUnicodeString(); + /*TODO(Andras) review if needed + if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name + fromStr = message->fromStrip(); // let's use that + */ + // TODO vcard + QString fromPart = StringUtil::emailAddrAsAnchor( fromStr, true, linkColor ); + if ( !vCardName.isEmpty() ) + fromPart += "  " + i18n("[vCard]") + ""; + //TDDO strategy date + //if ( strategy->showHeader( "date" ) ) + headerStr += + " \n" + " \n" + " " + " "; + } + + // to, cc, bcc + headerStr += + " " + " " + " " + " "; + + // header-bottom + headerStr += + "
"+message->subject()->asUnicodeString()+"
"+i18n("From: ")+""+ fromPart +"
"+i18nc("To field of the mail header.", "To: ")+"" + +headerPart+ + "
\n" + "
\n" + " \n" + "
\n"; + + // kmail icon + if( topLevel ) { + headerStr += + "
\n" + "\n" + "
\n"; + + // attachments + headerStr += + "
" + "
" + "
\n"; + } + + headerStr += "
"; + + // TODO + // spam status + // ### iterate over the rest of strategy->headerToDisplay() (or + // ### all headers if DefaultPolicy == Display) (elsewhere, too) + return headerStr; +} + +// ##################### + +// +// HeaderStyle abstract base: +// + +HeaderStyle::HeaderStyle() { + +} + +HeaderStyle::~HeaderStyle() { + +} + +const HeaderStyle * HeaderStyle::create( Type type ) { + switch ( type ) { + case Brief: return brief(); + case Plain: return plain(); + case Fancy: return fancy(); + case Enterprise: return enterprise(); + } + kFatal( 5006 ) <<"HeaderStyle::create(): Unknown header style ( type ==" + << (int)type << ") requested!"; + return 0; // make compiler happy +} + +const HeaderStyle * HeaderStyle::create( const QString & type ) { + QString lowerType = type.toLower(); + if ( lowerType == "brief" ) return brief(); + if ( lowerType == "plain" ) return plain(); + if ( lowerType == "enterprise" ) return enterprise(); + //if ( lowerType == "fancy" ) return fancy(); // not needed, see below + // don't kFatal here, b/c the strings are user-provided + // (KConfig), so fail gracefully to the default: + return fancy(); +} + +static const HeaderStyle * briefStyle = 0; +static const HeaderStyle * plainStyle = 0; +static const HeaderStyle * fancyStyle = 0; +static const HeaderStyle * enterpriseStyle = 0; + +const HeaderStyle * HeaderStyle::brief() { + if ( !briefStyle ) + briefStyle = new BriefHeaderStyle(); + return briefStyle; +} + +const HeaderStyle * HeaderStyle::plain() { + if ( !plainStyle ) + plainStyle = new PlainHeaderStyle(); + return plainStyle; +} + +const HeaderStyle * HeaderStyle::fancy() { + if ( !fancyStyle ) + fancyStyle = new FancyHeaderStyle(); + return fancyStyle; +} + +const HeaderStyle * HeaderStyle::enterprise() { + if ( !enterpriseStyle ) + enterpriseStyle = new EnterpriseHeaderStyle(); + return enterpriseStyle; +} + +QString HeaderStyle::dateStr(const KDateTime &dateTime) const +{ + KConfigGroup general( Global::instance()->config(), "General"); + time_t unixTime = dateTime.toTime_t(); +//kDebug()<<"#### Date ="<(general.readEntry( "dateFormat", + int( KMime::DateFormatter::Fancy ) )), + unixTime, general.readEntry( "customDateFormat" )); +} + +QByteArray HeaderStyle::dateShortStr(const KDateTime &dateTime) const +{ + time_t unixTime = dateTime.toTime_t(); + + QByteArray result = ctime(&unixTime); + + if (result[result.length()-1]=='\n') + result.truncate(result.length()-1); + + return result; +} + +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/headerstyle.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/headerstyle.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/headerstyle.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/headerstyle.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,96 @@ +/* -*- c++ -*- + headerstyle.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_HEADERSTYLE_H__ +#define __MESSAGEVIEWER_HEADERSTYLE_H__ +#include "messageviewer_export.h" +class QByteArray; +class QString; +class KDateTime; + +namespace KMime { + class Message; +} + +namespace MessageViewer { + +class HeaderStrategy; + +/** This class encapsulates the visual appearance of message + headers. Together with HeaderStrategy, which determines + which of the headers present in the message be shown, it is + responsible for the formatting of message headers. + + @short Encapsulates visual appearance of message headers. + @author Marc Mutz + @see HeaderStrategy +**/ +class MESSAGEVIEWER_EXPORT HeaderStyle { +protected: + HeaderStyle(); + virtual ~HeaderStyle(); + +public: + // + // Factory methods: + // + enum Type { Brief, Plain, Fancy, Enterprise }; + + static const HeaderStyle * create( Type type ); + static const HeaderStyle * create( const QString & type ); + + static const HeaderStyle * brief(); + static const HeaderStyle * plain(); + static const HeaderStyle * fancy(); + static const HeaderStyle * enterprise(); + + // + // Methods for handling the styles: + // + virtual const char * name() const = 0; + virtual const HeaderStyle * next() const = 0; + virtual const HeaderStyle * prev() const = 0; + + // + // HeaderStyle interface: + // + virtual QString format( KMime::Message * message, + const HeaderStrategy * strategy, + const QString & vCardName, + bool printing = false, bool topLevel = false ) const = 0; + + QString dateStr(const KDateTime &dateTime) const; + QByteArray dateShortStr(const KDateTime &dateTime) const; + +}; +} + +#endif // __MESSAGEVIEWER_HEADERSTYLE_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/htmlquotecolorer.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/htmlquotecolorer.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/htmlquotecolorer.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/htmlquotecolorer.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,121 @@ +/* Copyright 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "htmlquotecolorer.h" + +#include +#include +#include + +HTMLQuoteColorer::HTMLQuoteColorer() +{ +} + +QString HTMLQuoteColorer::process( const QString &htmlSource ) +{ + try { + // Create a DOM Document from the HTML source + DOM::HTMLDocument doc; + doc.open(); + doc.write( htmlSource ); + doc.close(); + + mIsQuotedLine = false; + mIsFirstTextNodeInLine = true; + processNode( doc.documentElement() ); + return doc.toString().string(); + } + catch( const DOM::DOMException &exception ) { + kWarning() << "Got a DOM exception with code" << exception.code; + kWarning() << "No quote coloring for you, then."; + return htmlSource; + } +} + +DOM::Node HTMLQuoteColorer::processNode( DOM::Node node ) +{ + // Below, we determine if the current text node should be quote colored by keeping track of + // linebreaks and whether this text node is the first one. + const QString textContent = node.textContent().string(); + const bool isTextNode = !textContent.isEmpty() && !node.hasChildNodes(); + if ( isTextNode ) { + if ( mIsFirstTextNodeInLine ) { + if ( textContent.simplified().startsWith( '>' ) || + textContent.simplified().startsWith( '|' ) ) { + mIsQuotedLine = true; + currentQuoteLength = quoteLength( textContent ) - 1; + } + else { + mIsQuotedLine = false; + } + } + + // All subsequent text nodes are not the first ones anymore + mIsFirstTextNodeInLine = false; + } + + const QString nodeName = node.nodeName().string().toLower(); + QStringList lineBreakNodes; + lineBreakNodes << "br" << "p" << "div" << "ul" << "ol" << "li"; + if ( lineBreakNodes.contains( nodeName ) ) { + mIsFirstTextNodeInLine = true; + } + + DOM::Node returnNode = node; + bool fontTagAdded = false; + if ( mIsQuotedLine && isTextNode ) { + + // Ok, we are in a line that should be quoted, so create a font node for the color and replace + // the current node with it. + DOM::Element font = node.ownerDocument().createElement( QString( "font" ) ); + font.setAttribute( QString( "color" ), mQuoteColors[ currentQuoteLength ].name() ); + node.parentNode().replaceChild( font, node ); + font.appendChild( node ); + returnNode = font; + fontTagAdded = true; + } + + // Process all child nodes, but only if we are didn't add those child nodes itself, as otherwise + // we'll go into an infinite recursion. + if ( !fontTagAdded ) { + DOM::Node childNode = node.firstChild(); + while ( !childNode.isNull() ) { + childNode = processNode( childNode ); + childNode = childNode.nextSibling(); + } + } + return returnNode; +} + +int HTMLQuoteColorer::quoteLength( const QString &line ) const +{ + QString simplified = line.simplified(); + simplified = simplified.replace( QRegExp( QLatin1String( "\\s" ) ), QString() ) + .replace( QLatin1Char( '|' ), QLatin1Char( '>' ) ); + if ( simplified.startsWith( ">>>" ) ) return 3; + if ( simplified.startsWith( ">>" ) ) return 2; + if ( simplified.startsWith( '>' ) ) return 1; + return 0; +} + +void HTMLQuoteColorer::setQuoteColor( int level, const QColor& color ) +{ + if ( level < 3 ) + mQuoteColors[level] = color; +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/htmlquotecolorer.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/htmlquotecolorer.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/htmlquotecolorer.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/htmlquotecolorer.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,65 @@ +/* Copyright 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef HTMLQUOTECOLORER_H +#define HTMLQUOTECOLORER_H + +#include +#include "messageviewer_export.h" +#include +//(laurent) remove export when we remove old kmail code +/** + * Little helper class that takes a HTML source as input and finds all + * lines that are quoted with '>' or '|'. The HTML text is then modified so + * that the quoted lines appear in the defined quote colors. + */ +class MESSAGEVIEWER_EXPORT HTMLQuoteColorer +{ + public: + + HTMLQuoteColorer(); + + /** + * Sets the quote color of the specific leve. + * This class supports 3 levels, from 0 to 2. + * Level 2 is the most quoted, with three quote signs in front of the line, and + * level 0 is the least quoted, with one quote sign in front of the line. + * + * If you don't call this, the color of the quoting will be black. + */ + void setQuoteColor( int level, const QColor &color ); + + /** + * Do the work and add nice colors to the HTML. + * @param htmlSource the input HTML code + * @return the modified HTML code + */ + QString process( const QString &htmlSource ); + + private: + + DOM::Node processNode( DOM::Node node ); + int quoteLength( const QString &line ) const; + + QColor mQuoteColors[3]; + bool mIsQuotedLine; + bool mIsFirstTextNodeInLine; + int currentQuoteLength; +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/htmlstatusbar.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/htmlstatusbar.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/htmlstatusbar.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/htmlstatusbar.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,152 @@ +/* -*- c++ -*- + htmlstatusbar.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2002 Ingo Kloecker + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "htmlstatusbar.h" +#include "global.h" +#include "globalsettings.h" + +#include +#include +#include +#include + +#include +#include +#include + +HtmlStatusBar::HtmlStatusBar( QWidget * parent, const char * name, Qt::WFlags f ) + : QLabel( parent, f ), + mMode( Normal ) +{ + setObjectName( name ); + setAlignment( Qt::AlignHCenter | Qt::AlignTop ); + // Don't force a minimum height to the reader widget + setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ) ); + setAutoFillBackground( true ); + update(); +} + +HtmlStatusBar::~HtmlStatusBar() {} + +void HtmlStatusBar::update() { + QPalette pal = palette(); + pal.setColor( backgroundRole(), bgColor() ); + pal.setColor( foregroundRole(), fgColor() ); + setPalette( pal ); + setText( message() ); +} + +void HtmlStatusBar::setNormalMode() { + setMode( Normal ); +} + +void HtmlStatusBar::setHtmlMode() { + setMode( Html ); +} + +void HtmlStatusBar::setNeutralMode() { + setMode( Neutral ); +} + +void HtmlStatusBar::setMode( Mode m ) { + if ( m == mode() ) + return; + mMode = m; + update(); +} + +QString HtmlStatusBar::message() const { + switch ( mode() ) { + case Html: // bold: "HTML Message" + return i18n( "
H
T
M
L
" + "
M
e
s
s
a
g
e
" ); + case Normal: // normal: "No HTML Message" + return i18n( "
N
o
" + "
H
T
M
L
" + "
M
e
s
s
a
g
e
" ); + default: + case Neutral: + return QString(); + } +} + + +QColor HtmlStatusBar::fgColor() const { + KConfigGroup conf( Global::instance()->config(), "Reader" ); + QColor defaultColor, color; + switch ( mode() ) { + case Html: + defaultColor = Qt::white; + color = defaultColor; + if ( !GlobalSettings::self()->useDefaultColors() ) { + color = conf.readEntry( "ColorbarForegroundHTML", defaultColor ); + } + return color; + case Normal: + defaultColor = Qt::black; + color = defaultColor; + if ( !GlobalSettings::self()->useDefaultColors() ) { + color = conf.readEntry( "ColorbarForegroundPlain", defaultColor ); + } + return color; + default: + case Neutral: + return Qt::black; + } +} + +QColor HtmlStatusBar::bgColor() const { + KConfigGroup conf( Global::instance()->config(), "Reader" ); + + QColor defaultColor, color; + switch ( mode() ) { + case Html: + defaultColor = Qt::black; + color = defaultColor; + if ( !GlobalSettings::self()->useDefaultColors() ) { + color = conf.readEntry( "ColorbarBackgroundHTML", defaultColor ); + } + return color; + case Normal: + defaultColor = Qt::lightGray; + color = defaultColor; + if ( !GlobalSettings::self()->useDefaultColors() ) { + color = conf.readEntry( "ColorbarBackgroundPlain", defaultColor ); + } + return color; + default: + case Neutral: + return Qt::white; + } +} + +#include "htmlstatusbar.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/htmlstatusbar.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/htmlstatusbar.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/htmlstatusbar.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/htmlstatusbar.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,100 @@ +/* -*- c++ -*- + htmlstatusbar.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2002 Ingo Kloecker + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ +#ifndef _MESSAGEVIEWER_HTMLSTATUSBAR_H_ +#define _MESSAGEVIEWER_HTMLSTATUSBAR_H_ + +#include +#include "messageviewer_export.h" +class QString; +class QColor; + + +/** + * @short The HTML statusbar widget for use with the reader. + * + * The HTML status bar is a small widget that acts as an indicator + * for the message content. It can be in one of two modes: + * + *
+ *
Normal
+ *
Default. No HTML.
+ *
Neutral
+ *
Temporary value. Used while the real mode is undetermined.
+ *
Html
+ *
HTML content is being shown. Since HTML mails can mimic all sorts + * of KMail markup in the reader, this provides out-of-band information + * about the presence of (rendered) HTML.
+ *
+ * + * @author Ingo Kloecker , Marc Mutz + **/ +//Laurent remove export when we remove old code in kmail (temporary) +class MESSAGEVIEWER_EXPORT HtmlStatusBar : public QLabel { + Q_OBJECT +public: + explicit HtmlStatusBar( QWidget * parent=0, const char * name=0, Qt::WFlags f=0 ); + virtual ~HtmlStatusBar(); + + enum Mode { + Normal, + Html, + Neutral + }; + + /** @return current mode. */ + Mode mode() const { return mMode ; } + bool isHtml() const { return mode() == Html ; } + bool isNormal() const { return mode() == Normal ; } + bool isNeutral() const { return mode() == Neutral ; } + + // Update the status bar, for example when the color scheme changed. + void update(); + +public slots: + /** Switch to "html mode". */ + void setHtmlMode(); + /** Switch to "normal mode". */ + void setNormalMode(); + /** Switch to "neutral" mode (currently == normal mode). */ + void setNeutralMode(); + /** Switch to mode @p m */ + void setMode( Mode m ); + +private: + QString message() const; + QColor bgColor() const; + QColor fgColor() const; + + Mode mMode; +}; + +#endif // _KMAIL_HTMLSTATUSBAR_H_ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/iconnamecache.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/iconnamecache.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/iconnamecache.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/iconnamecache.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,54 @@ +/* Copyright 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "iconnamecache.h" + +#include +#include + +namespace MessageViewer { +K_GLOBAL_STATIC( IconNameCache, s_iconNameCache ) + +IconNameCache* IconNameCache::instance() +{ + return s_iconNameCache; +} + +bool IconNameCache::Entry::operator < ( const Entry &other ) const +{ + const int fileNameCompare = fileName.compare( other.fileName ); + if ( fileNameCompare != 0 ) + return fileNameCompare < 0; + else + return size < other.size; +} + +QString IconNameCache::iconPath( const QString &name, int size ) const +{ + Entry entry; + entry.fileName = name; + entry.size = size; + + if ( mCachedEntries.contains( entry ) ) + return mCachedEntries.value( entry ); + + const QString fileName = KIconLoader::global()->iconPath( name, size ); + mCachedEntries.insert( entry, fileName ); + return fileName; +} +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/iconnamecache.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/iconnamecache.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/iconnamecache.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/iconnamecache.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,55 @@ +/* Copyright 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef ICONNAMECACHE_H +#define ICONNAMECACHE_H + +#include "messageviewer_export.h" +#include +#include + +/** + * This class is a replacement for KIconLoader::iconPath(), because the iconPath() + * function can be slow for non-existing icons or icons that fall back to a generic icon. + * Reason is that KIconLoader does slow system calls for finding the icons. + * + * The IconNameCache caches the result of iconPath() in a map and solves the slowness. + */ +namespace MessageViewer { +class MESSAGEVIEWER_EXPORT IconNameCache +{ + public: + + static IconNameCache *instance(); + QString iconPath( const QString &name, int size ) const; + + private: + + class Entry + { + public: + QString fileName; + int size; + + bool operator < ( const Entry &other ) const; + }; + + mutable QMap mCachedEntries; +}; +} +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/bodypartformatter.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/bodypartformatter.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/bodypartformatter.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/bodypartformatter.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,94 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + bodypartformatter.h + + This file is part of KMail's plugin interface. + Copyright (c) 2004 Marc Mutz , + Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KMAIL_INTERFACE_BODYPARTFORMATTER_H__ +#define __KMAIL_INTERFACE_BODYPARTFORMATTER_H__ + +namespace MessageViewer { + + class HtmlWriter; + +namespace Interface { + + class BodyPart; + class BodyPartURLHandler; + + class BodyPartFormatter { + 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 + @li Failed returned when formatting failed. Currently equivalent to Ok + */ + enum Result { Ok, NeedContent, AsIcon, Failed }; + + /** + Format body part \a part by generating some HTML and writing + that to \a writer. + + @return the result code (see above) + */ + virtual Result format( BodyPart * part, HtmlWriter * writer ) const = 0; + }; + + /** + @short interface for BodyPartFormatter plugins + + The interface is queried by for types, subtypes, and the + corresponding bodypart formatter, and the result inserted into + the bodypart formatter factory. + + Subtype alone or both type and subtype may be "*", which is + taken as a wildcard, so that e.g. type=text subtype=* matches + any text subtype, but with lesser specificity than a concrete + mimetype such as text/plain. type=* is only allowed when + subtype=*, too. + */ + class BodyPartFormatterPlugin { + public: + virtual ~BodyPartFormatterPlugin() {} + + virtual const BodyPartFormatter * bodyPartFormatter( int idx ) const = 0; + virtual const char * type( int idx ) const = 0; + virtual const char * subtype( int idx ) const = 0; + + virtual const BodyPartURLHandler * urlHandler( int idx ) const = 0; + }; + +} // namespace Interface + +} +#endif // __KMAIL_INTERFACE_BODYPARTFORMATTER_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/bodypart.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/bodypart.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/bodypart.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/bodypart.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,165 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + bodypart.h + + This file is part of KMail's plugin interface. + Copyright (c) 2004 Marc Mutz , + Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KMAIL_INTERFACES_BODYPART_H__ +#define __KMAIL_INTERFACES_BODYPART_H__ + +class QByteArray; +class QString; + +namespace MessageViewer { +namespace Interface { + +/*FIXME(Andras) review, port + class Observer; + class Observable; +*/ + /** + @short interface of classes that implement status for BodyPartFormatters. + */ + class BodyPartMemento { + public: + virtual ~BodyPartMemento() {} +#if 0 +//FIXME(Andras) review, port + /** If your BodyPartMemento implementation also implements the + Observer interface, simply implement these as + return this;, else as return + 0;. This is needed to avoid forcing a dependency of + plugins on internal KMail classes. + */ + virtual Observer * asObserver() = 0; + + /** If your BodyPartMemento implementation also implements the + Observable interface, simply implement these as + return this;, else as return + 0;. This is needed to avoid forcing a dependency of + plugins on internal KMail classes. + */ + virtual Observable * asObservable() = 0; +#endif + }; + + /** + @short interface of message body parts. + */ + class BodyPart { + public: + virtual ~BodyPart() {} + + /** + @return a string respresentation of an URL that can be used + to invoke a BodyPartURLHandler for this body part. + */ + virtual QString makeLink( const QString & path ) const = 0; + + /** + @return the decoded (CTE, canonicalisation, and charset + encoding undone) text contained in the body part, or + QString(), it the body part is not of type "text". + */ + virtual QString asText() const = 0; + + /** + @return the decoded (CTE undone) content of the body part, or + a null array if this body part instance is of type text. + */ + virtual QByteArray asBinary() const = 0; + + /** + @return the value of the content-type header field parameter + with name \a parameter, or QString(), if that that + parameter is not present in the body's content-type header + field. RFC 2231 encoding is removed first. + + Note that this method will suppress queries to certain + standard parameters (most notably "charset") to keep plugins + decent. + + Note2 that this method preserves the case of the parameter + value returned. So, if the parameter you want to use defines + the value to be case-insensitive (such as the smime-type + parameter), you need to make sure you do the casemap yourself + before comparing to a reference value. + */ + virtual QString contentTypeParameter( const char * parameter ) const = 0; + + /** + @return the content of the content-description header field, + or QString() if that header is not present in this body + part. RFC 2047 encoding is decoded first. + */ + virtual QString contentDescription() const = 0; + + //virtual int contentDisposition() const = 0; + /** + @return the value of the content-disposition header field + parameter with name \a parameter, or QString() if that + parameter is not present in the body's content-disposition + header field. RFC 2231 encoding is removed first. + + The notes made for contentTypeParameter() above apply here as + well. + */ + virtual QString contentDispositionParameter( const char * parameter ) const = 0; + + /** + @return whether this part already has it's complete body + fetched e.g. from an IMAP server. + */ + virtual bool hasCompleteBody() const = 0; + + /** + @return the BodyPartMemento set for this part, or null, if + none is set. + */ + virtual BodyPartMemento * memento() const = 0; + + /** + @return register an implementation of the BodyPartMemento + interface as a status object with this part. + */ + virtual void setBodyPartMemento( BodyPartMemento * ) = 0; + + enum Display { None, AsIcon, Inline }; + /** + @return whether this body part should be displayed iconic or inline + */ + virtual Display defaultDisplay() const = 0; + }; + +} // namespace Interface + +} + +#endif // __KMAIL_INTERFACES_BODYPART_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/bodyparturlhandler.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/bodyparturlhandler.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/bodyparturlhandler.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/bodyparturlhandler.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,106 @@ +/* -*- c++ -*- + interfaces/bodyparturlhandler.h + + This file is part of KMail's plugin interface. + Copyright (c) 2003, 2004 Marc Mutz + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KMAIL_INTERFACE_BODYPARTURLHANDLER_H__ +#define __KMAIL_INTERFACE_BODYPARTURLHANDLER_H__ + +class QString; +class QPoint; + +class Callback; + +namespace MessageViewer { + +namespace Interface { + + class BodyPart; + + /** + * @short An interface to body part reader link handlers + * @author Marc Mutz + * + * This interface is a condensed of variant of the more general + * @see URLHandler interface, designed to make bodypart-dependent + * link operations possible without exposing KMail-internal + * classes. + * + * Implementation-wise, these handlers are called as a nested + * Chain Of Responsibilty by an internal implementation of + * URLHandler. + * + * You can create a link whose handling is passed to this handler + * by using BodyPart::makeLink( const QString & path ). \a path is + * what * is passed back to the methods of this interface. + * + * Note that the BodyPart interface does not provide a means of + * learning the content type of the body part passed. This is + * intentional. It is expected that either separate + * BodyPartURLHandlers are created for these purposes or else the + * information encoded into the path parameter by the + * BodyPartFormatter. + */ + class BodyPartURLHandler { + public: + virtual ~BodyPartURLHandler() {} + + /** Called when LMB-clicking on a link in the reader. Should + start processing equivalent to "opening" the link. + + @return true if the click was handled by this handler, false + otherwise. + */ + virtual bool handleClick( BodyPart * part, const QString & path, Callback& c ) const = 0; + + /** 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. + + @return true if the right-click was handled by this handler, + false otherwise. + */ + virtual bool handleContextMenuRequest( BodyPart * part, const QString & path, const QPoint & p ) const = 0; + + /** Called when hovering over a link. + + @return a string to be shown in the status bar while + hovering over this link or QString() if the link was not + handled by this handler. + */ + virtual QString statusBarMessage( BodyPart * part, const QString & path ) const = 0; + }; + +} // namespace Interface + +} + +#endif // __KMAIL_INTERFACES_BODYPARTURLHANDLER_H__ + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/htmlwriter.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/htmlwriter.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/htmlwriter.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/htmlwriter.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,120 @@ +/* -*- c++ -*- + interfaces/htmlwriter.h + + This file is part of KMail's plugin interface. + Copyright (c) 2003 Marc Mutz + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KMAIL_INTERFACES_HTMLWRITER_H__ +#define __KMAIL_INTERFACES_HTMLWRITER_H__ + +class QByteArray; +class QString; + +namespace MessageViewer { +/** + * @short An interface for HTML sinks. + * @author Marc Mutz + * + */ +namespace Interface { + class HtmlWriter { + public: + virtual ~HtmlWriter() {} + + /** Signal the begin of stuff to write, and give the CSS definitions */ + virtual void begin( const QString & cssDefinitions ) = 0; + /** Write out a chunk of text. No HTML escaping is performed. */ + virtual void write( const QString & html ) = 0; + /** Signal the end of stuff to write. */ + virtual void end() = 0; + }; +} + +/** + * @short An interface to HTML sinks + * @author Marc Mutz + * + * @deprecated KMail should be ported to Interface::HtmlWriter. This + * interface exposes internal working models. The queuing + * vs. writing() issues exposed here should be hidden by using two + * different implementations of KHTMLPartHtmlWriter: one for + * queuing, and one for writing. This should be fixed before the + * release, so we an keep the plugin interface stable. + * + * Operate this interface in one and only one of the following two + * modes: + * + * @section Sync Mode + * + * In sync mode, use #begin() to initiate a session, then + * #write() some chunks of HTML code and finally #end() the session. + * + * @section Async Mode + * + * In async mode, use #begin() to initialize a session, then + * #queue() some chunks of HTML code and finally end the + * session by calling #flush(). + * + * Queued HTML code is fed to the html sink using a timer. For this + * to work, control must return to the event loop so timer events + * are delivered. + * + * @section Combined mode + * + * You may combine the two modes in the following way only. Any + * number of #write() calls can precede #queue() calls, + * but once a chunk has been queued, you @em must @em not + * #write() more data, only #queue() it. + * + * Naturally, whenever you queued data in a given session, that + * session must be ended by calling #flush(), not #end(). + */ +class HtmlWriter : public Interface::HtmlWriter { +public: + virtual ~HtmlWriter() {} + + /** Stop all possibly pending processing in order to be able to + * call #begin() again. */ + virtual void reset() = 0; + + virtual void queue( const QString & str ) = 0; + /** (Start) flushing internal buffers, if any. */ + virtual void flush() = 0; + + /** + * Embed a part with Content-ID @p contentId, using url @p url. + */ + virtual void embedPart( const QByteArray & contentId, const QString & url ) = 0; +}; + +} + + +#endif // __KMAIL_INTERFACES_HTMLWRITER_H__ + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/urlhandler.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/urlhandler.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/interfaces/urlhandler.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/interfaces/urlhandler.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,86 @@ +/* -*- c++ -*- + interfaces/urlhandler.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KMAIL_INTERFACES_URLHANDLER_H__ +#define __KMAIL_INTERFACES_URLHANDLER_H__ + +class KUrl; + +class QString; +class QPoint; + +namespace MessageViewer { + +class ViewerPrivate; + +/** + * @short An interface to reader link handlers + * @author Marc Mutz + * + * The KMReaderWin parameters are temporary until such time as + * the Memento-store is in place. + */ +class URLHandler { +public: + virtual ~URLHandler() {} + + /** + * Called when LMB-clicking on a link in the reader. Should start + * processing equivalent to "opening" the link. + * + * @return true if the click was handled by this URLHandler, + * false otherwise. + */ + virtual bool handleClick( const KUrl & url, ViewerPrivate * w ) const = 0; + + /** + * 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. + * + * @return true if the right-click was handled by this + * URLHandler, false otherwise. + */ + virtual bool handleContextMenuRequest( const KUrl & url, const QPoint & p, ViewerPrivate * w ) const = 0; + + /** + * Called when hovering over a link. + * + * @return a string to be shown in the status bar while hoverin + * over this link. + */ + virtual QString statusBarMessage( const KUrl & url, ViewerPrivate * w ) const = 0; +}; + +} + +#endif // __KMAIL_INTERFACES_URLHANDLER_H__ + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/kcursorsaver.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/kcursorsaver.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/kcursorsaver.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/kcursorsaver.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,61 @@ +#ifndef kcursorsaver_h +#define kcursorsaver_h + +#include +#include +#include "messageviewer_export.h" +/** + * @short sets a cursor and makes sure it's restored on destruction + * Create a KCursorSaver object when you want to set the cursor. + * As soon as it gets out of scope, it will restore the original + * cursor. + */ +class MESSAGEVIEWER_EXPORT KCursorSaver +{ +public: + /// constructor taking QCursor shapes + KCursorSaver(Qt::CursorShape shape) { + QApplication::setOverrideCursor( QCursor(shape) ); + inited = true; + } + + /// copy constructor. The right side won't restore the cursor + KCursorSaver( const KCursorSaver &rhs ) { + *this = rhs; + } + + /// restore the cursor + ~KCursorSaver() { + if (inited) + QApplication::restoreOverrideCursor(); + } + + /// call this to explitly restore the cursor + inline void restoreCursor(void) { + QApplication::restoreOverrideCursor(); + inited = false; + } + +protected: + void operator=( const KCursorSaver &rhs ) { + inited = rhs.inited; + rhs.inited = false; + } + +private: + mutable bool inited; +}; + +/** + * convenience functions + */ +namespace KBusyPtr { + inline KCursorSaver idle() { + return KCursorSaver(Qt::ArrowCursor); + } + inline KCursorSaver busy() { + return KCursorSaver(Qt::WaitCursor); + } +} + +#endif /*kbusyptr_h_*/ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/khtmlparthtmlwriter.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/khtmlparthtmlwriter.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/khtmlparthtmlwriter.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/khtmlparthtmlwriter.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,154 @@ +/* -*- c++ -*- + khtmlparthtmlwriter.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + + +#include "khtmlparthtmlwriter.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +KHtmlPartHtmlWriter::KHtmlPartHtmlWriter( KHTMLPart * part, + QObject * parent, const char * name ) + : QObject( parent ), HtmlWriter(), + mHtmlPart( part ), mState( Ended ) +{ + setObjectName( name ); + assert( part ); + mHtmlTimer.setSingleShot( true ); + connect( &mHtmlTimer, SIGNAL(timeout()), SLOT(slotWriteNextHtmlChunk()) ); +} + +KHtmlPartHtmlWriter::~KHtmlPartHtmlWriter() { + +} + +void KHtmlPartHtmlWriter::begin( const QString & css ) { + if ( mState != Ended ) { + kWarning() <<"KHtmlPartHtmlWriter: begin() called on non-ended session!"; + reset(); + } + + mEmbeddedPartMap.clear(); + + // clear the widget: + mHtmlPart->view()->setUpdatesEnabled( false ); + mHtmlPart->view()->viewport()->setUpdatesEnabled( false ); + mHtmlPart->view()->ensureVisible( 0, 0 ); + + mHtmlPart->begin( KUrl() ); + if ( !css.isEmpty() ) + mHtmlPart->setUserStyleSheet( css ); + mState = Begun; +} + +void KHtmlPartHtmlWriter::end() { + kWarning( mState != Begun, 5006 ) <<"KHtmlPartHtmlWriter: end() called on non-begun or queued session!"; + mHtmlPart->end(); + + resolveCidUrls(); + + mHtmlPart->view()->viewport()->setUpdatesEnabled( true ); + mHtmlPart->view()->setUpdatesEnabled( true ); + mHtmlPart->view()->viewport()->repaint(); + mState = Ended; + emit finished(); +} + +void KHtmlPartHtmlWriter::reset() { + if ( mState != Ended ) { + mHtmlTimer.stop(); + mHtmlQueue.clear(); + mState = Begun; // don't run into end()'s warning + end(); + mState = Ended; + } +} + +void KHtmlPartHtmlWriter::write( const QString & str ) { + kWarning( mState != Begun, 5006 ) <<"KHtmlPartHtmlWriter: write() called in Ended or Queued state!"; + mHtmlPart->write( str ); +} + +void KHtmlPartHtmlWriter::queue( const QString & str ) { + static const uint chunksize = 16384; + for ( int pos = 0 ; pos < str.length() ; pos += chunksize ) + mHtmlQueue.push_back( str.mid( pos, chunksize ) ); + mState = Queued; +} + +void KHtmlPartHtmlWriter::flush() { + slotWriteNextHtmlChunk(); +} + +void KHtmlPartHtmlWriter::slotWriteNextHtmlChunk() { + if ( mHtmlQueue.empty() ) { + mState = Begun; // don't run into end()'s warning + end(); + } else { + mHtmlPart->write( mHtmlQueue.front() ); + mHtmlQueue.pop_front(); + mHtmlTimer.start( 0 ); + } +} + +void KHtmlPartHtmlWriter::embedPart( const QByteArray & contentId, + const QString & contentURL ) { + mEmbeddedPartMap[QString(contentId)] = contentURL; +} + +void KHtmlPartHtmlWriter::resolveCidUrls() +{ + DOM::HTMLDocument document = mHtmlPart->htmlDocument(); + DOM::HTMLCollection images = document.images(); + for ( DOM::Node node = images.firstItem(); !node.isNull(); node = images.nextItem() ) { + DOM::HTMLImageElement image( node ); + KUrl url( image.src().string() ); + if ( url.protocol() == "cid" ) { + EmbeddedPartMap::const_iterator it = mEmbeddedPartMap.constFind( url.path() ); + if ( it != mEmbeddedPartMap.constEnd() ) { + kDebug() <<"Replacing" << url.prettyUrl() <<" by" << it.value(); + image.setSrc( it.value() ); + } + } + } +} + + +#include "khtmlparthtmlwriter.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/khtmlparthtmlwriter.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/khtmlparthtmlwriter.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/khtmlparthtmlwriter.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/khtmlparthtmlwriter.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,86 @@ +/* -*- c++ -*- + khtmlparthtmlwriter.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_KHTMLPARTHTMLWRITER_H__ +#define __MESSAGEVIEWER_KHTMLPARTHTMLWRITER_H__ + +#include "interfaces/htmlwriter.h" +#include "messageviewer_export.h" +#include + +#include +#include +#include +#include + +class QString; +class KHTMLPart; + +//Laurent remove export when we remove old code +class MESSAGEVIEWER_EXPORT KHtmlPartHtmlWriter : public QObject, public MessageViewer::HtmlWriter { + Q_OBJECT +public: + // Key is Content-Id, value is URL + typedef QMap EmbeddedPartMap; + explicit KHtmlPartHtmlWriter( KHTMLPart * part, + QObject * parent=0, const char * name = 0 ); + virtual ~KHtmlPartHtmlWriter(); + + void begin( const QString & cssDefs ); + void end(); + void reset(); + void write( const QString & str ); + void queue( const QString & str ); + void flush(); + void embedPart( const QByteArray & contentId, const QString & url ); + +signals: + void finished(); + +private slots: + void slotWriteNextHtmlChunk(); + +private: + void resolveCidUrls(); + +private: + KHTMLPart * mHtmlPart; + QStringList mHtmlQueue; + QTimer mHtmlTimer; + enum State { + Begun, + Queued, + Ended + } mState; + EmbeddedPartMap mEmbeddedPartMap; +}; + +#endif // __MESSAGEVIEWER_KHTMLPARTHTMLWRITER_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/kleojobexecutor.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/kleojobexecutor.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/kleojobexecutor.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/kleojobexecutor.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,160 @@ +/* + Copyright (c) 2008 Volker Krause + + 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) any later version. + + 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. +*/ + +#include "kleojobexecutor.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +using namespace Kleo; +using namespace GpgME; +using boost::shared_ptr; + +KleoJobExecutor::KleoJobExecutor( QObject* parent ) : QObject( parent ) +{ + setObjectName( "KleoJobExecutor" ); + mEventLoop = new QEventLoop( this ); +} + + +GpgME::VerificationResult KleoJobExecutor::exec( + Kleo::VerifyDetachedJob* job, + const QByteArray & signature, + const QByteArray & signedData ) +{ + kDebug() << "Starting detached verification job"; + connect( job, SIGNAL(result(GpgME::VerificationResult)), + SLOT(verificationResult(GpgME::VerificationResult)) ); + GpgME::Error err = job->start( signature, signedData ); + if ( err ) + return VerificationResult( err ); + mEventLoop->exec( QEventLoop::ExcludeUserInputEvents ); + return mVerificationResult; +} + +GpgME::VerificationResult KleoJobExecutor::exec( + Kleo::VerifyOpaqueJob * job, + const QByteArray & signedData, + QByteArray & plainText ) +{ + kDebug() << "Starting opaque verification job"; + connect( job, SIGNAL(result(GpgME::VerificationResult,QByteArray)), + SLOT(verificationResult(GpgME::VerificationResult,QByteArray)) ); + GpgME::Error err = job->start( signedData ); + if ( err ) { + plainText.clear(); + return VerificationResult( err ); + } + mEventLoop->exec( QEventLoop::ExcludeUserInputEvents ); + plainText = mData; + return mVerificationResult; +} + +std::pair< GpgME::DecryptionResult, GpgME::VerificationResult > KleoJobExecutor::exec( + Kleo::DecryptVerifyJob * job, + const QByteArray & cipherText, + QByteArray & plainText ) +{ + kDebug() << "Starting decryption job"; + connect( job, SIGNAL(result(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray)), + SLOT(decryptResult(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray)) ); + GpgME::Error err = job->start( cipherText ); + if ( err ) { + plainText.clear(); + return std::make_pair( DecryptionResult( err ), VerificationResult( err ) ); + } + mEventLoop->exec( QEventLoop::ExcludeUserInputEvents ); + plainText = mData; + return std::make_pair( mDecryptResult, mVerificationResult ); +} + +GpgME::ImportResult KleoJobExecutor::exec(Kleo::ImportJob* job, const QByteArray & certData) +{ + connect( job, SIGNAL(result(GpgME::ImportResult)), SLOT(importResult(GpgME::ImportResult)) ); + GpgME::Error err = job->start( certData ); + if ( err ) + return ImportResult( err ); + mEventLoop->exec( QEventLoop::ExcludeUserInputEvents ); + return mImportResult; +} + +void KleoJobExecutor::verificationResult(const GpgME::VerificationResult & result) +{ + kDebug() << "Detached verification job finished"; + Kleo::Job * job = dynamic_cast( sender() ); + assert(job); + mVerificationResult = result; + mAuditLogError = job->auditLogError(); + mAuditLog = job->auditLogAsHtml(); + mEventLoop->quit(); +} + +void KleoJobExecutor::verificationResult(const GpgME::VerificationResult & result, const QByteArray & plainText) +{ + kDebug() << "Opaque verification job finished"; + Kleo::Job * job = dynamic_cast( sender() ); + assert(job); + mVerificationResult = result; + mData = plainText; + mAuditLogError = job->auditLogError(); + mAuditLog = job->auditLogAsHtml(); + mEventLoop->quit(); +} + +void KleoJobExecutor::decryptResult( + const GpgME::DecryptionResult & decryptionresult, + const GpgME::VerificationResult & verificationresult, + const QByteArray & plainText ) +{ + kDebug() << "Decryption job finished"; + Kleo::Job * job = dynamic_cast( sender() ); + assert(job); + mVerificationResult = verificationresult; + mDecryptResult = decryptionresult; + mData = plainText; + mAuditLogError = job->auditLogError(); + mAuditLog = job->auditLogAsHtml(); + mEventLoop->quit(); +} + +void KleoJobExecutor::importResult(const GpgME::ImportResult & result) +{ + Kleo::Job * job = dynamic_cast( sender() ); + assert(job); + mImportResult = result; + mAuditLogError = job->auditLogError(); + mAuditLog = job->auditLogAsHtml(); + mEventLoop->quit(); +} + + +QString KleoJobExecutor::auditLogAsHtml() const +{ + return mAuditLog; +} + +#include "kleojobexecutor.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/kleojobexecutor.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/kleojobexecutor.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/kleojobexecutor.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/kleojobexecutor.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,82 @@ +/* + Copyright (c) 2008 Volker Krause + + 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) any later version. + + 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. +*/ + +#ifndef _MESSAGEVIEWER_KLEOJOBEXECUTOR_H +#define _MESSAGEVIEWER_KLEOJOBEXECUTOR_H + +#include "messageviewer_export.h" + +#include +#include +#include + +#include + +#include + +class QEventLoop; + +namespace Kleo { + class DecryptVerifyJob; + class ImportJob; + class VerifyDetachedJob; + class VerifyOpaqueJob; +} + +/** + Helper class for synchronous execution of Kleo crypto jobs. +*/ +class MESSAGEVIEWER_EXPORT KleoJobExecutor : public QObject +{ + Q_OBJECT + public: + KleoJobExecutor( QObject *parent = 0 ); + + GpgME::VerificationResult exec( Kleo::VerifyDetachedJob* job, + const QByteArray &signature, + const QByteArray &signedData ); + GpgME::VerificationResult exec( Kleo::VerifyOpaqueJob* job, + const QByteArray &signedData, + QByteArray &plainText ); + std::pair exec( Kleo::DecryptVerifyJob *job, + const QByteArray &cipherText, + QByteArray &plainText ); + GpgME::ImportResult exec( Kleo::ImportJob* job, const QByteArray &certData ); + + GpgME::Error auditLogError() const { return mAuditLogError; } + QString auditLogAsHtml() const; + + private slots: + void verificationResult( const GpgME::VerificationResult &result ); + void verificationResult( const GpgME::VerificationResult &result, const QByteArray &plainText ); + void decryptResult( const GpgME::DecryptionResult & decryptionresult, + const GpgME::VerificationResult & verificationresult, + const QByteArray & plainText ); + void importResult( const GpgME::ImportResult &result ); + + private: + QEventLoop *mEventLoop; + GpgME::VerificationResult mVerificationResult; + GpgME::DecryptionResult mDecryptResult; + GpgME::ImportResult mImportResult; + QByteArray mData; + GpgME::Error mAuditLogError; + QString mAuditLog; +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/kmaddrbook.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/kmaddrbook.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/kmaddrbook.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/kmaddrbook.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,131 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + * kmail: KDE mail client + * Copyright (c) 1996-1998 Stefan Taferner + * + * 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) any later version. + * + * 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. + * + */ +#include "kmaddrbook.h" +#include "kcursorsaver.h" + +#include +#include + +#include +#include +#include + +#include + +#include + +void KabcBridge::addresses(QStringList& result) // includes lists +{ + KCursorSaver busy(KBusyPtr::busy()); // loading might take a while + + KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true ); + KABC::AddressBook::ConstIterator it; + for( it = addressBook->constBegin(); it != addressBook->constEnd(); ++it ) { + const QStringList emails = (*it).emails(); + QString n = (*it).prefix() + ' ' + + (*it).givenName() + ' ' + + (*it).additionalName() + ' ' + + (*it).familyName() + ' ' + + (*it).suffix(); + n = n.simplified(); + + QRegExp needQuotes("[^ 0-9A-Za-z\\x0080-\\xFFFF]"); + QString endQuote = "\" "; + QStringList::ConstIterator mit; + QString addr, email; + + for ( mit = emails.begin(); mit != emails.end(); ++mit ) { + email = *mit; + if (!email.isEmpty()) { + if (n.isEmpty() || (email.contains( '<' ) )) + addr.clear(); + else { // do we really need quotes around this name ? + if (n.contains(needQuotes) ) + addr = '"' + n + endQuote; + else + addr = n + ' '; + } + + if (!addr.isEmpty() && !(email.contains( '<' ) ) + && !(email.contains( '>' ) ) + && !(email.contains( ',' ) )) + addr += '<' + email + '>'; + else + addr += email; + addr = addr.trimmed(); + result.append( addr ); + } + } + } + + result += addressBook->allDistributionListNames(); + + result.sort(); +} + +QStringList KabcBridge::addresses() +{ + QStringList entries; + KABC::AddressBook::ConstIterator it; + + const KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true ); + for( it = addressBook->begin(); it != addressBook->end(); ++it ) { + entries += (*it).fullEmail(); + } + return entries; +} + +//----------------------------------------------------------------------------- +QString KabcBridge::expandNickName( const QString& nickName ) +{ + if ( nickName.isEmpty() ) + return QString(); + + const QString lowerNickName = nickName.toLower(); + const KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true ); + for( KABC::AddressBook::ConstIterator it = addressBook->begin(); + it != addressBook->end(); ++it ) { + if ( (*it).nickName().toLower() == lowerNickName ) + return (*it).fullEmail(); + } + return QString(); +} + + +//----------------------------------------------------------------------------- + +QStringList KabcBridge::categories() +{ + KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true ); + KABC::Addressee::List addresses = addressBook->allAddressees(); + QStringList allcategories, aux; + + for ( KABC::Addressee::List::Iterator it = addresses.begin(); + it != addresses.end(); ++it ) { + aux = ( *it ).categories(); + for ( QStringList::ConstIterator itAux = aux.constBegin(); + itAux != aux.constEnd(); ++itAux ) { + // don't have duplicates in allcategories + if ( !allcategories.contains( *itAux ) ) + allcategories += *itAux; + } + } + return allcategories; +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/kmaddrbook.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/kmaddrbook.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/kmaddrbook.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/kmaddrbook.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,42 @@ +/* + * kmail: KDE mail client + * Copyright (c) 1996-1998 Stefan Taferner + * + * 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) any later version. + * + * 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. + * + */ +#ifndef KMAddrBook_h +#define KMAddrBook_h + +#include "messageviewer_export.h" +#include + +#include + + +class MESSAGEVIEWER_EXPORT KabcBridge { +public: + static QStringList addresses(); + static void addresses(QStringList& result); + static QString expandNickName( const QString& nickName ); + /** + Returns all categories found in the addressbook. + @return A list of the categories + */ + static QStringList categories(); +}; + + +#endif /*KMAddrBook_h*/ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/kmmsgpartdlg.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/kmmsgpartdlg.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/kmmsgpartdlg.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/kmmsgpartdlg.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,599 @@ +// kmmsgpartdlg.cpp + + +// my includes: +#include "kmmsgpartdlg.h" +#include "nodehelper.h" + +// other KMail includes: +#include "kcursorsaver.h" + +// other kdenetwork includes: (none) + +// other KDE includes: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// other Qt includes: +#include +#include +#include +#include +#include +#include + +// other includes: +#include + +static const struct { + KMMsgPartDialog::Encoding encoding; + const char * displayName; +} encodingTypes[] = { + { KMMsgPartDialog::SevenBit, I18N_NOOP2("message encoding type", "None (7-bit text)") }, + { KMMsgPartDialog::EightBit, I18N_NOOP2("message encoding type", "None (8-bit text)") }, + { KMMsgPartDialog::QuotedPrintable, I18N_NOOP2("message encoding type", "Quoted Printable") }, + { KMMsgPartDialog::Base64, I18N_NOOP2("message encoding type", "Base 64") }, +}; +static const int numEncodingTypes = + sizeof encodingTypes / sizeof *encodingTypes; + +QByteArray autoDetectCharset(const QByteArray &_encoding, const QStringList &encodingList, const QString &text); +QByteArray encodeRFC2231String( const QString& _str, const QByteArray& charset ); +const QTextCodec* codecForName(const QByteArray& _str); +QByteArray toUsAscii(const QString& _str, bool *ok = 0); + +KMMsgPartDialog::KMMsgPartDialog( const QString & caption, + QWidget * parent ) + : KDialog( parent ) +{ + setCaption( caption.isEmpty() ? i18n("Message Part Properties") : caption ); + setButtons( Ok|Cancel|Help ); + setDefaultButton( Ok ); + setModal( true ); + showButtonSeparator( true ); + + // tmp vars: + QGridLayout * glay; + QLabel * label; + QString msg; + + setHelp( QString::fromLatin1("attachments") ); + + for ( int i = 0 ; i < numEncodingTypes ; ++i ) + mI18nizedEncodings << i18nc( "message encoding type", encodingTypes[i].displayName ); + QFrame *frame = new QFrame( this ); + setMainWidget( frame ); + glay = new QGridLayout(frame ); + glay->setSpacing( spacingHint() ); + glay->setColumnStretch( 1, 1 ); + glay->setRowStretch( 8, 1 ); + + // mimetype icon: + mIcon = new QLabel( frame ); + mIcon->setPixmap( DesktopIcon("unknown") ); + glay->addWidget( mIcon, 0, 0, 2, 1); + + // row 0: Type combobox: + mMimeType = new KComboBox( true, frame ); + mMimeType->setInsertPolicy( KComboBox::NoInsert ); + mMimeType->setValidator( new KMimeTypeValidator( mMimeType ) ); + mMimeType->addItems( QStringList() + << QString::fromLatin1("text/html") + << QString::fromLatin1("text/plain") + << QString::fromLatin1("image/gif") + << QString::fromLatin1("image/jpeg") + << QString::fromLatin1("image/png") + << QString::fromLatin1("application/octet-stream") + << QString::fromLatin1("application/x-gunzip") + << QString::fromLatin1("application/zip") ); + connect( mMimeType, SIGNAL(editTextChanged(const QString&)), + this, SLOT(slotMimeTypeChanged(const QString&)) ); + glay->addWidget( mMimeType, 0, 1 ); + + msg = i18n("

The MIME type of the file:

" + "

normally, you do not need to touch this setting, since the " + "type of the file is automatically checked; but, sometimes, %1 " + "may not detect the type correctly -- here is where you can fix " + "that.

", KGlobal::mainComponent().aboutData()->programName() ); + mMimeType->setWhatsThis( msg ); + + // row 1: Size label: + mSize = new QLabel( frame ); + setSize( KIO::filesize_t(0) ); + glay->addWidget( mSize, 1, 1 ); + + msg = i18n("

The size of the part:

" + "

sometimes, %1 will only give an estimated size here, " + "because calculating the exact size would take too much time; " + "when this is the case, it will be made visible by adding " + "\"(est.)\" to the size displayed.

", + KGlobal::mainComponent().aboutData()->programName() ); + mSize->setWhatsThis( msg ); + + // row 2: "Name" lineedit and label: + mFileName = new KLineEdit( frame ); + mFileName->setClearButtonShown( true ); + label = new QLabel( i18nc("file name of the attachment.", "&Name:"), frame ); + label->setBuddy( mFileName ); + glay->addWidget( label, 2, 0 ); + glay->addWidget( mFileName, 2, 1 ); + + msg = i18n("

The file name of the part:

" + "

although this defaults to the name of the attached file, " + "it does not specify the file to be attached; rather, it " + "suggests a file name to be used by the recipient's mail agent " + "when saving the part to disk.

"); + label->setWhatsThis( msg ); + mFileName->setWhatsThis( msg ); + + // row 3: "Description" lineedit and label: + mDescription = new KLineEdit( frame ); + mDescription->setClearButtonShown( true ); + label = new QLabel( i18n("&Description:"), frame ); + label->setBuddy( mDescription ); + glay->addWidget( label, 3, 0 ); + glay->addWidget( mDescription, 3, 1 ); + + msg = i18n("

A description of the part:

" + "

this is just an informational description of the part, " + "much like the Subject is for the whole message; most " + "mail agents will show this information in their message " + "previews alongside the attachment's icon.

"); + label->setWhatsThis( msg ); + mDescription->setWhatsThis( msg ); + + // row 4: "Encoding" combobox and label: + mEncoding = new KComboBox( frame ); + mEncoding->setEditable( false ); + mEncoding->addItems( mI18nizedEncodings ); + label = new QLabel( i18n("&Encoding:"), frame ); + label->setBuddy( mEncoding ); + glay->addWidget( label, 4, 0 ); + glay->addWidget( mEncoding, 4, 1 ); + + msg = i18n("

The transport encoding of this part:

" + "

normally, you do not need to change this, since %1 will use " + "a decent default encoding, depending on the MIME type; yet, " + "sometimes, you can significantly reduce the size of the " + "resulting message, e.g. if a PostScript file does not contain " + "binary data, but consists of pure text -- in this case, choosing " + "\"quoted-printable\" over the default \"base64\" will save up " + "to 25% in resulting message size.

", + KGlobal::mainComponent().aboutData()->programName() ); + label->setWhatsThis( msg ); + mEncoding->setWhatsThis( msg ); + + // row 5: "Suggest automatic display..." checkbox: + mInline = new QCheckBox( i18n("Suggest &automatic display"), frame ); + glay->addWidget( mInline, 5, 0, 1, 2 ); + + msg = i18n("

Check this option if you want to suggest to the " + "recipient the automatic (inline) display of this part in the " + "message preview, instead of the default icon view;

" + "

technically, this is carried out by setting this part's " + "Content-Disposition header field to \"inline\" " + "instead of the default \"attachment\".

"); + mInline->setWhatsThis( msg ); + + // row 6: "Sign" checkbox: + mSigned = new QCheckBox( i18n("&Sign this part"), frame ); + glay->addWidget( mSigned, 6, 0, 1, 2 ); + + msg = i18n("

Check this option if you want this message part to be " + "signed;

" + "

the signature will be made with the key that you associated " + "with the currently-selected identity.

"); + mSigned->setWhatsThis( msg ); + + // row 7: "Encrypt" checkbox: + mEncrypted = new QCheckBox( i18n("Encr&ypt this part"), frame ); + glay->addWidget( mEncrypted, 7, 0, 1, 2 ); + + msg = i18n("

Check this option if you want this message part to be " + "encrypted;

" + "

the part will be encrypted for the recipients of this " + "message

"); + mEncrypted->setWhatsThis( msg ); + // (row 8: spacer) +} + + +KMMsgPartDialog::~KMMsgPartDialog() {} + + +QString KMMsgPartDialog::mimeType() const { + return mMimeType->currentText(); +} + +void KMMsgPartDialog::setMimeType( const QString & mimeType ) { + for ( int i = 0 ; i < mMimeType->count() ; ++i ) + if ( mMimeType->itemText( i ) == mimeType ) { + mMimeType->setCurrentIndex( i ); + slotMimeTypeChanged( mimeType ); + return; + } + mMimeType->insertItem( 0, mimeType ); + mMimeType->setCurrentIndex( 0 ); + slotMimeTypeChanged( mimeType ); +} + +void KMMsgPartDialog::setMimeType( const QString & type, + const QString & subtype ) { + setMimeType( QString::fromLatin1("%1/%2").arg(type).arg(subtype) ); +} + +void KMMsgPartDialog::setMimeTypeList( const QStringList & mimeTypes ) { + mMimeType->addItems( mimeTypes ); +} + +void KMMsgPartDialog::setSize( KIO::filesize_t size, bool estimated ) { + QString text = KIO::convertSize( size ); + if ( estimated ) + text = i18nc("%1: a filesize incl. unit (e.g. \"1.3 KB\")", + "%1 (est.)", text ); + mSize->setText( text ); +} + +QString KMMsgPartDialog::fileName() const { + return mFileName->text(); +} + +void KMMsgPartDialog::setFileName( const QString & fileName ) { + mFileName->setText( fileName ); +} + +QString KMMsgPartDialog::description() const { + return mDescription->text(); +} + +void KMMsgPartDialog::setDescription( const QString & description ) { + mDescription->setText( description ); +} + +KMMsgPartDialog::Encoding KMMsgPartDialog::encoding() const { + QString s = mEncoding->currentText(); + for ( int i = 0 ; i < mI18nizedEncodings.count() ; ++i ) + if ( s == mI18nizedEncodings.at(i) ) + return encodingTypes[i].encoding; + kFatal(5006) <<"KMMsgPartDialog::encoding(): Unknown encoding encountered!"; + return None; // keep compiler happy +} + +void KMMsgPartDialog::setEncoding( Encoding encoding ) { + for ( int i = 0 ; i < numEncodingTypes ; ++i ) + if ( encodingTypes[i].encoding == encoding ) { + QString text = mI18nizedEncodings.at(i); + for ( int j = 0 ; j < mEncoding->count() ; ++j ) + if ( mEncoding->itemText(j) == text ) { + mEncoding->setCurrentIndex( j ); + return; + } + mEncoding->insertItem( 0, text ); + mEncoding->setCurrentIndex( 0 ); + } + kFatal(5006) <<"KMMsgPartDialog::setEncoding():" + "Unknown encoding encountered!"; +} + +void KMMsgPartDialog::setShownEncodings( int encodings ) { + mEncoding->clear(); + for ( int i = 0 ; i < numEncodingTypes ; ++i ) + if ( encodingTypes[i].encoding & encodings ) + mEncoding->addItem( mI18nizedEncodings.at(i) ); +} + +bool KMMsgPartDialog::isInline() const { + return mInline->isChecked(); +} + +void KMMsgPartDialog::setInline( bool inlined ) { + mInline->setChecked( inlined ); +} + +bool KMMsgPartDialog::isEncrypted() const { + return mEncrypted->isChecked(); +} + +void KMMsgPartDialog::setEncrypted( bool encrypted ) { + mEncrypted->setChecked( encrypted ); +} + +void KMMsgPartDialog::setCanEncrypt( bool enable ) { + mEncrypted->setEnabled( enable ); +} + +bool KMMsgPartDialog::isSigned() const { + return mSigned->isChecked(); +} + +void KMMsgPartDialog::setSigned( bool sign ) { + mSigned->setChecked( sign ); +} + +void KMMsgPartDialog::setCanSign( bool enable ) { + mSigned->setEnabled( enable ); +} + +void KMMsgPartDialog::slotMimeTypeChanged( const QString & mimeType ) { + // message subparts MUST have 7bit or 8bit encoding... +#if 0 + // ...but until KMail can recode 8bit messages on attach, so that + // they can be signed, we can't enforce this :-( + if ( mimeType.startsWith("message/") ) { + setEncoding( SevenBit ); + mEncoding->setEnabled( false ); + } else { + mEncoding->setEnabled( !mReadOnly ); + } +#endif + // find a mimetype icon: + KMimeType::Ptr mt = KMimeType::mimeType( mimeType, KMimeType::ResolveAliases ); + if ( !mt.isNull() ) + mIcon->setPixmap( KIconLoader::global()->loadMimeTypeIcon( mt->iconName(), + KIconLoader::Desktop ) ); + else + mIcon->setPixmap( DesktopIcon("unknown") ); +} + + + + +KMMsgPartDialogCompat::KMMsgPartDialogCompat( const char *, bool readOnly) + : KMMsgPartDialog(), mMsgPart( 0 ) +{ + setShownEncodings( SevenBit|EightBit|QuotedPrintable|Base64 ); + if (readOnly) + { + mMimeType->setEditable(false); + mMimeType->setEnabled(false); + mFileName->setReadOnly(true); + mDescription->setReadOnly(true); + mEncoding->setEnabled(false); + mInline->setEnabled(false); + mEncrypted->setEnabled(false); + mSigned->setEnabled(false); + } + connect(this,SIGNAL(okClicked()),SLOT(slotOk())); +} + +KMMsgPartDialogCompat::~KMMsgPartDialogCompat() {} + +void KMMsgPartDialogCompat::setMsgPart( KMime::Content * aMsgPart ) +{ + mMsgPart = aMsgPart; + assert( mMsgPart ); + + QByteArray enc = mMsgPart->contentTransferEncoding()->as7BitString(); + if ( enc == "7bit" ) + setEncoding( SevenBit ); + else if ( enc == "8bit" ) + setEncoding( EightBit ); + else if ( enc == "quoted-printable" ) + setEncoding( QuotedPrintable ); + else + setEncoding( Base64 ); + + setDescription( mMsgPart->contentDescription()->asUnicodeString() ); + setFileName( mMsgPart->contentDisposition()->filename() ); + setMimeType( mMsgPart->contentType()->mediaType(), mMsgPart->contentType()->subType() ); + setSize( mMsgPart->decodedContent().size() ); + QString cd(mMsgPart->contentDisposition()->asUnicodeString()); + setInline( cd.indexOf( QRegExp("^\\s*inline", Qt::CaseInsensitive) ) >= 0 ); +} + + +void KMMsgPartDialogCompat::applyChanges() +{ + if (!mMsgPart) return; + + KCursorSaver busy(KBusyPtr::busy()); + + // apply Content-Disposition: + QByteArray cDisp; + if ( isInline() ) + cDisp = "inline;"; + else + cDisp = "attachment;"; + + QString name = fileName(); + if ( !name.isEmpty() || !mMsgPart->contentType()->name().isEmpty()) { + mMsgPart->contentType()->setName( name, mMsgPart->contentType()->charset()); //FIXME(Andras) check if the second arg is ok + QByteArray encoding = autoDetectCharset( mMsgPart->contentType()->charset(), QStringList() + /*KMMessage::preferredCharsets()*/, name ); //FIXME(Andras) read the pref charset + if ( encoding.isEmpty() ) encoding = "utf-8"; + QByteArray encName = encodeRFC2231String( name, encoding ); + + cDisp += "\n\tfilename"; + if ( name != QString( encName ) ) + cDisp += "*=" + encName; + else + cDisp += "=\"" + encName.replace( '\\', "\\\\" ).replace( '"', "\\\"" ) + '"'; + mMsgPart->contentDisposition()->from7BitString( cDisp ); + } + + // apply Content-Description" + QString desc = description(); + if ( !desc.isEmpty() || !mMsgPart->contentDescription()->asUnicodeString().isEmpty() ) + mMsgPart->contentDescription()->fromUnicodeString( desc, mMsgPart->contentDescription()->defaultCharset() ); + + // apply Content-Type: + QByteArray type = mimeType().toLatin1(); + QByteArray subtype; + int idx = type.indexOf('/'); + if ( idx < 0 ) + subtype = ""; + else { + subtype = type.mid( idx+1 ); + type = type.left( idx ); + } + mMsgPart->contentType()->setMimeType( type + "/" + subtype ); + + // apply Content-Transfer-Encoding: + QByteArray cte; + if (subtype == "rfc822" && type == "message") + kWarning( encoding() != SevenBit && encoding() != EightBit, 5006 ) + << "encoding on rfc822/message must be \"7bit\" or \"8bit\""; + switch ( encoding() ) { + case SevenBit: cte = "7bit"; break; + case EightBit: cte = "8bit"; break; + case QuotedPrintable: cte = "quoted-printable"; break; + case Base64: default: cte = "base64"; break; + } + if ( cte != mMsgPart->contentTransferEncoding()->as7BitString().toLower() ) { + QByteArray body = mMsgPart->decodedContent(); + mMsgPart->contentTransferEncoding()->from7BitString( cte ); + mMsgPart->setBody( body ); + } +} + + +//----------------------------------------------------------------------------- +void KMMsgPartDialogCompat::slotOk() +{ + applyChanges(); +} + +QByteArray autoDetectCharset(const QByteArray &_encoding, const QStringList &encodingList, const QString &text) +{ + QStringList charsets = encodingList; + if (!_encoding.isEmpty()) + { + QString currentCharset = QString::fromLatin1(_encoding); + charsets.removeAll(currentCharset); + charsets.prepend(currentCharset); + } + + QStringList::ConstIterator it = charsets.constBegin(); + for (; it != charsets.constEnd(); ++it) + { + QByteArray encoding = (*it).toLatin1(); + if (encoding == "locale") + { + encoding = NodeHelper::instance()->localCodec()->name(); + kAsciiToLower(encoding.data()); + } + if (text.isEmpty()) + return encoding; + if (encoding == "us-ascii") { + bool ok; + (void) toUsAscii(text, &ok); + if (ok) + return encoding; + } + else + { + const QTextCodec *codec = codecForName(encoding); + if (!codec) { + kDebug() <<"Auto-Charset: Something is wrong and I can not get a codec. [" << encoding <<"]"; + } else { + if (codec->canEncode(text)) + return encoding; + } + } + } + return 0; +} + +QByteArray encodeRFC2231String( const QString& _str, + const QByteArray& charset ) +{ + static const QByteArray especials = "()<>@,;:\"/[]?.= \033"; + + if ( _str.isEmpty() ) + return QByteArray(); + + QByteArray cset; + if ( charset.isEmpty() ) + { + cset = NodeHelper::instance()->localCodec()->name(); + kAsciiToLower( cset.data() ); + } + else + cset = charset; + const QTextCodec *codec = codecForName( cset ); + QByteArray latin; + if ( charset == "us-ascii" ) + latin = toUsAscii( _str ); + else if ( codec ) + latin = codec->fromUnicode( _str ); + else + latin = _str.toLocal8Bit(); + + char *l; + for ( l = latin.data(); *l; ++l ) { + if ( ( ( *l & 0xE0 ) == 0 ) || ( *l & 0x80 ) ) + // *l is control character or 8-bit char + break; + } + if ( !*l ) + return latin; + + QByteArray result = cset + "''"; + for ( l = latin.data(); *l; ++l ) { + bool needsQuoting = ( *l & 0x80 ) || ( *l == '%' ); + if( !needsQuoting ) { + int len = especials.length(); + for ( int i = 0; i < len; i++ ) + if ( *l == especials[i] ) { + needsQuoting = true; + break; + } + } + if ( needsQuoting ) { + result += '%'; + unsigned char hexcode; + hexcode = ( ( *l & 0xF0 ) >> 4 ) + 48; + if ( hexcode >= 58 ) + hexcode += 7; + result += hexcode; + hexcode = ( *l & 0x0F ) + 48; + if ( hexcode >= 58 ) + hexcode += 7; + result += hexcode; + } else { + result += *l; + } + } + return result; +} + +//----------------------------------------------------------------------------- +const QTextCodec* codecForName(const QByteArray& _str) +{ + if (_str.isEmpty()) + return 0; + QByteArray codec = _str; + kAsciiToLower(codec.data()); + return KGlobal::charsets()->codecForName(codec); +} + +QByteArray toUsAscii(const QString& _str, bool *ok) +{ + bool all_ok =true; + QString result = _str; + int len = result.length(); + for (int i = 0; i < len; i++) + if (result.at(i).unicode() >= 128) { + result[i] = '?'; + all_ok = false; + } + if (ok) + *ok = all_ok; + return result.toLatin1(); +} + + + +//----------------------------------------------------------------------------- +#include "kmmsgpartdlg.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/kmmsgpartdlg.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/kmmsgpartdlg.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/kmmsgpartdlg.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/kmmsgpartdlg.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,164 @@ +/* + * kmail: KDE mail client + * Copyright (c) 1996-1998 Stefan Taferner + * + * 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) any later version. + * + * 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. + * + */ +#ifndef kmmsgpartdlg_h +#define kmmsgpartdlg_h + +#include +#include + +namespace KMime { + class Content; +} +class KComboBox; +class KLineEdit; + +class QCheckBox; +class QLabel; + +#undef None + +/** @short GUI for KMMsgPartDialog + @author Marc Mutz +*/ +class KMMsgPartDialog: public KDialog +{ + Q_OBJECT + +public: + explicit KMMsgPartDialog( const QString & caption=QString(), + QWidget * parent=0 ); + virtual ~KMMsgPartDialog(); + + /** Get the currently selected mimetype */ + QString mimeType() const; + /** Sets the mime type to be displayed. */ + void setMimeType( const QString & type, const QString & subtype ); + /** This is an overloaded member function, provided for + convenience. It behaves essentially like the above function. + + Sets the mime type to be displayed, but only if @p mimeType + passes KMimeTypeValidator's test. */ + void setMimeType( const QString & mimeType ); + /** Sets the initial list of mime types to be displayed in the + combobox. The items are @em not validated. */ + void setMimeTypeList( const QStringList & mimeTypes ); + + /** Sets the size of the file to be attached in bytes. This is + strictly informational and thus can't be queried. If @p approx + is true, the size is an estimation based on typical */ + void setSize( KIO::filesize_t size, bool estimated=false ); + + /** Returns the current file name of the attachment. Note that this + doesn't define which file is being attached. It only defines + what the attachment's filename parameter should contain. */ + QString fileName() const; + /** Sets the file name of the attachment. Note that this doesn't + define which file is being attached. It only defines what the + attachment's filename parameter should contain. */ + void setFileName( const QString & fileName ); + + /** Returns the content of the Content-Description header + field. This field is only informational. */ + QString description() const; + /** Sets the description of the attachment, ie. the content of the + Content-Description header field. */ + void setDescription( const QString & description ); + + /** The list of supported encodings */ + enum Encoding { + None = 0x00, + SevenBit = 0x01, + EightBit = 0x02, + QuotedPrintable = 0x04, + Base64 = 0x08 + }; + + /** Returns the current encoding */ + Encoding encoding() const; + /** Sets the encoding to use */ + void setEncoding( Encoding encoding ); + /** Sets the list of encodings to be shown. @p encodings is the + bitwise OR of Encoding flags */ + void setShownEncodings( int encodings ); + + /** Returns true if the attchment has a content-disposition of + "inline", false otherwise. */ + bool isInline() const; + /** Sets whether this attachment has a content-disposition of + "inline" */ + void setInline( bool inlined ); + + /** Returns whether or not this attachment is or shall be encrypted */ + bool isEncrypted() const; + /** Sets whether or not this attachment is or should be encrypted */ + void setEncrypted( bool encrypted ); + /** Sets whether or not this attachment can be encrypted */ + void setCanEncrypt( bool enable ); + + /** Returns whether or not this attachment is or shall be signed */ + bool isSigned() const; + /** Sets whether or not this attachment is or should be signed */ + void setSigned( bool sign ); + /** Sets whether or not this attachment can be signed */ + void setCanSign( bool enable ); + +protected slots: + void slotMimeTypeChanged( const QString & mimeType ); + +protected: + KComboBox *mMimeType; + QLabel *mIcon; + QLabel *mSize; + KLineEdit *mFileName; + KLineEdit *mDescription; + KComboBox *mEncoding; + QCheckBox *mInline; + QCheckBox *mEncrypted; + QCheckBox *mSigned; + QStringList mI18nizedEncodings; +}; + +/** @short The attachment dialog with convenience backward compatible methods + @author Marc Mutz +*/ +class KMMsgPartDialogCompat : public KMMsgPartDialog { + Q_OBJECT +public: + explicit KMMsgPartDialogCompat( const char * caption=0, bool=false ); + virtual ~KMMsgPartDialogCompat(); + + /** Display information about this message part. */ + void setMsgPart(KMime::Content* msgPart); + + /** Returns the (possibly modified) message part. */ + KMime::Content* msgPart(void) const { return mMsgPart; } + +protected slots: + void slotOk(); + +protected: + /** Applies changes from the dialog to the message part. Called + when the Ok button is pressed. */ + void applyChanges(void); + + KMime::Content *mMsgPart; +}; + +#endif /*kmmsgpartdlg_h*/ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/mailsourceviewer.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/mailsourceviewer.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/mailsourceviewer.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/mailsourceviewer.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,102 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + * + * This file is part of KMail, the KDE mail client. + * + * Copyright (c) 2002-2003 Carsten Pfeiffer + * Copyright (c) 2003 Zack Rusin + * + * KMail is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * KMail 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 + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of this program with any edition of + * the Qt library by Trolltech AS, Norway (or with modified versions + * of Qt that use the same license as Qt), and distribute linked + * combinations including the two. You must obey the GNU General + * Public License in all respects for all of the code used other than + * Qt. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from + * your version. + */ +#include "mailsourceviewer.h" +#include +#include +#include + +#include +#include +#include +namespace MessageViewer { + +void MailSourceHighlighter::highlightBlock ( const QString & text ) { + // all visible ascii except space and : + const QRegExp regexp( "^([\\x21-9;-\\x7E]+:\\s)" ); + const int headersState = -1; // Also the initial State + const int bodyState = 0; + + // keep the previous state + setCurrentBlockState( previousBlockState() ); + // If a header is found + if( regexp.indexIn( text ) != -1 ) + { + // Content- header starts a new mime part, and therefore new headers + // If a Content-* header is found, change State to headers until a blank line is found. + if ( text.startsWith( QLatin1String( "Content-" ) ) ) + { + setCurrentBlockState( headersState ); + } + // highligth it if in headers state + if( ( currentBlockState() == headersState ) ) + { + QFont font = document()->defaultFont (); + font.setBold( true ); + setFormat( 0, regexp.matchedLength(), font ); + } + } + // Change to body state + else if ( text.isEmpty() ) + { + setCurrentBlockState( bodyState ); + } +} + +MailSourceViewer::MailSourceViewer( QWidget *parent ) + : KTextBrowser( parent ), mSourceHighLighter( 0 ) +{ + setAttribute( Qt::WA_DeleteOnClose ); + setLineWrapMode( QTextEdit::NoWrap ); + setTextInteractionFlags( Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard ); + + // combining the shortcuts in one qkeysequence() did not work... + QShortcut* shortcut = new QShortcut( this ); + shortcut->setKey( Qt::Key_Escape ); + connect( shortcut, SIGNAL( activated() ), SLOT( close() ) ); + + shortcut = new QShortcut( this ); + shortcut->setKey( Qt::Key_W+Qt::CTRL ); + connect( shortcut, SIGNAL( activated() ), SLOT( close() ) ); + KWindowSystem::setIcons( winId(), + qApp->windowIcon().pixmap( IconSize( KIconLoader::Desktop ), + IconSize( KIconLoader::Desktop ) ), + qApp->windowIcon().pixmap( IconSize( KIconLoader::Small ), + IconSize( KIconLoader::Small ) ) ); + mSourceHighLighter = new MailSourceHighlighter( this ); +} + +MailSourceViewer::~MailSourceViewer() +{ + delete mSourceHighLighter; mSourceHighLighter = 0; +} + +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/mailsourceviewer.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/mailsourceviewer.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/mailsourceviewer.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/mailsourceviewer.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,72 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + * + * This file is part of KMail, the KDE mail client. + * + * Copyright (c) 2002-2003 Carsten Pfeiffer + * Copyright (c) 2003 Zack Rusin + * + * KMail is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * KMail 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 + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of this program with any edition of + * the Qt library by Trolltech AS, Norway (or with modified versions + * of Qt that use the same license as Qt), and distribute linked + * combinations including the two. You must obey the GNU General + * Public License in all respects for all of the code used other than + * Qt. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from + * your version. + */ +#ifndef MAILSOURCEVIEWER_H +#define MAILSOURCEVIEWER_H + +#include "messageviewer_export.h" + +#include + +#include + +/** + * A tiny little class to use for displaying raw messages, textual + * attachments etc. + * + * Auto-deletes itself when closed. + * + * @author Carsten Pfeiffer + */ +namespace MessageViewer { +class MailSourceHighlighter : public QSyntaxHighlighter +{ +public: + MailSourceHighlighter( KTextBrowser* browser ) + : QSyntaxHighlighter( browser ) + {} +protected: + virtual void highlightBlock ( const QString & text ); +}; + + +class MESSAGEVIEWER_EXPORT MailSourceViewer : public KTextBrowser +{ +public: + MailSourceViewer( QWidget *parent = 0 ); + ~MailSourceViewer(); + +private: + MailSourceHighlighter *mSourceHighLighter; +}; + +} +#endif // MAILSOURCEVIEWER_H diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/Messages.sh /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/Messages.sh --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/Messages.sh 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/Messages.sh 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT *.cpp -o $podir/libmessageviewer.pot diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/messageviewer_export.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/messageviewer_export.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/messageviewer_export.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/messageviewer_export.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,38 @@ +/* This file is part of the KDE project + Copyright (C) 2007 David Faure + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MESSAGEVIEWER_EXPORT_H +#define MESSAGEVIEWER_EXPORT_H + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include + +#ifndef MESSAGEVIEWER_EXPORT +# if defined(MAKE_MESSAGEVIEWER_LIB) + /* We are building this library */ +# define MESSAGEVIEWER_EXPORT KDE_EXPORT +# else + /* We are using this library */ +# define MESSAGEVIEWER_EXPORT KDE_IMPORT +# endif +#endif + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/messageviewer.kcfg /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/messageviewer.kcfg --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/messageviewer.kcfg 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/messageviewer.kcfg 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,134 @@ + + + qtextcodec.h + kglobalsettings.h + kcolorscheme.h + + + + + true + + + KGlobalSettings::fixedFont() + + + + + + + true + + + QString( QTextCodec::codecForLocale()->name() ).toLower() == "eucjp" ? QString("jis7") : QString( QTextCodec::codecForLocale()->name() ).toLower() + + Some emails, especially those generated automatically, do not specify the character encoding which needs to be used to properly display them. In such cases a fallback character encoding will be used, which you can configure here. Set it to the character encoding most commonly used in your part of the world. As a default the encoding configured for the whole system is used. + + + + + + Changing this from its default 'Auto' will force the use of the specified encoding for all emails, regardless of what they specify themselves. + + + + false + + + + + + true + + + + + + true + + Enable this if you want smileys like :-) appearing in the message text to be replaced by emoticons (small pictures). + + + false + + Enable this option to show different levels of quoted text. Disable to hide the levels of quoted text. + + + + 3 + 0 + 10 + + + + false + + Enable this option to show quoted text with a smaller font. + + + + + + + + + + false + + Enable this option to get the User-Agent and X-Mailer header lines displayed when using fancy headers. + + + + true + + + + false + + + + + false + + + + + + + + + + + + + + bottom + + + + + + + + + + + + + Never + + + + + + + + true + + + + + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/mimetreemodel.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/mimetreemodel.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/mimetreemodel.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/mimetreemodel.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,209 @@ +/* + Copyright (c) 2007, 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "mimetreemodel.h" + +#include + +#include +#include +#include +#include + +Q_DECLARE_METATYPE(KMime::Content*) +Q_DECLARE_METATYPE(KMime::ContentIndex) + +class MimeTreeModel::Private +{ + public: + Private() : + root ( 0 ) + {} + + // FIXME: this should actually be a member function of ContentIndex + int contentIndexUp( KMime::ContentIndex &index ) + { + Q_ASSERT( index.isValid() ); + QStringList ids = index.toString().split( QLatin1Char('.') ); + QString lastId = ids.takeLast(); + index = KMime::ContentIndex( ids.join( QLatin1String(".") ) ); + return lastId.toInt(); + } + + QString descriptionForContent( KMime::Content *content ) + { + if ( content->hasHeader( "Subject" ) ) + return content->getHeaderByType( "Subject" )->asUnicodeString(); + if ( content->contentDescription( false ) ) { + const QString desc = content->contentDescription()->asUnicodeString(); + if ( !desc.isEmpty() ) + return desc; + } + if ( content->contentType( false ) ) { + const QString name = content->contentType()->name(); + if ( !name.isEmpty() ) + return name; + } + return i18n( "body part" ); + } + + QString typeForContent( KMime::Content *content ) + { + if ( !content->contentType( false ) ) + return QString(); + KMimeType::Ptr mimeType = KMimeType::mimeType( QString::fromLatin1( content->contentType()->mimeType() ) ); + if ( mimeType.isNull() ) + return QString::fromLatin1( content->contentType()->mimeType() ); + return mimeType->comment(); + } + + QString sizeOfContent( KMime::Content *content ) + { + if ( content->body().isEmpty() ) + return QString(); + return KGlobal::locale()->formatByteSize( content->body().size() ); + } + + KIcon iconForContent( KMime::Content *content ) + { + if ( !content->contentType( false ) ) + return KIcon(); + KMimeType::Ptr mimeType = KMimeType::mimeType( QString::fromLatin1( content->contentType()->mimeType() ) ); + if ( mimeType.isNull() || mimeType->iconName().isEmpty() ) + return KIcon(); + return KIcon( mimeType->iconName() ); + } + + KMime::Content *root; +}; + +MimeTreeModel::MimeTreeModel(QObject * parent) : + QAbstractItemModel( parent ), + d ( new Private ) +{ +} + +MimeTreeModel::~ MimeTreeModel() +{ + delete d; +} + +void MimeTreeModel::setRoot(KMime::Content * root) +{ + d->root = root; + reset(); +} + +QModelIndex MimeTreeModel::index(int row, int column, const QModelIndex &parent) const +{ + if ( !parent.isValid() ) { + if ( row != 0 ) + return QModelIndex(); + return createIndex( row, column, d->root ); + } + + KMime::Content *parentContent = static_cast( parent.internalPointer() ); + if ( !parentContent || parentContent->contents().count() <= row || row < 0 ) + return QModelIndex(); + KMime::Content *content = parentContent->contents().at( row ); + return createIndex( row, column, content ); +} + +QModelIndex MimeTreeModel::parent(const QModelIndex & index) const +{ + if ( !index.isValid() ) + return QModelIndex(); + KMime::Content *currentContent = static_cast( index.internalPointer() ); + if ( !currentContent ) + return QModelIndex(); + + KMime::ContentIndex currentIndex = d->root->indexForContent( currentContent ); + if ( !currentIndex.isValid() ) + return QModelIndex(); + d->contentIndexUp( currentIndex ); + KMime::Content *parentContent = d->root->content( currentIndex ); + int row = 0; + if ( currentIndex.isValid() ) + row = d->contentIndexUp( currentIndex ) - 1; // 1 based -> 0 based + + return createIndex( row, 0, parentContent ); +} + +int MimeTreeModel::rowCount(const QModelIndex & parent) const +{ + if ( !d->root ) + return 0; + if ( !parent.isValid() ) + return 1; + KMime::Content *parentContent = static_cast( parent.internalPointer() ); + if ( parentContent ) + return parentContent->contents().count(); + return 0; +} + +int MimeTreeModel::columnCount(const QModelIndex & parent) const +{ + Q_UNUSED( parent ); + return 3; +} + +QVariant MimeTreeModel::data(const QModelIndex & index, int role) const +{ + KMime::Content *content = static_cast( index.internalPointer() ); + if ( !content ) + return QVariant(); + if ( role == Qt::ToolTipRole ) + // TODO + return d->root->indexForContent( content ).toString(); + if ( role == Qt::DisplayRole ) { + switch( index.column() ) { + case 0: + return d->descriptionForContent( content ); + case 1: + return d->typeForContent( content ); + case 2: + return d->sizeOfContent( content ); + } + } + if ( role == Qt::DecorationRole && index.column() == 0 ) { + return d->iconForContent( content ); + } + if ( role == ContentIndexRole ) + return QVariant::fromValue( d->root->indexForContent( content ) ); + if ( role == ContentRole ) + return QVariant::fromValue( content ); + return QVariant(); +} + +QVariant MimeTreeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) { + switch ( section ) { + case 0: + return i18n( "Description" ); + case 1: + return i18n( "Type" ); + case 2: + return i18n( "Size" ); + } + } + return QAbstractItemModel::headerData( section, orientation, role ); +} + +#include "mimetreemodel.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/mimetreemodel.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/mimetreemodel.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/mimetreemodel.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/mimetreemodel.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,60 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef MAILVIEWER_MIMETREEMODEL_H +#define MAILVIEWER_MIMETREEMODEL_H + +#include + +namespace KMime { + class Content; +} + + +/** + A model representing the mime part tree of a message. +*/ +class MimeTreeModel : public QAbstractItemModel +{ + Q_OBJECT + + public: + enum Role { + ContentIndexRole = Qt::UserRole + 1, + ContentRole + }; + MimeTreeModel( QObject *parent = 0 ); + ~MimeTreeModel(); + + void setRoot( KMime::Content *root ); + + QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const; + QModelIndex parent( const QModelIndex &index ) const; + int rowCount( const QModelIndex &parent = QModelIndex() ) const; + int columnCount( const QModelIndex &parent = QModelIndex() ) const; + QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const; + QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; + + private: + class Private; + Private* const d; +}; + + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/nodehelper.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/nodehelper.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/nodehelper.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/nodehelper.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,638 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ +#include "nodehelper.h" +#include "iconnamecache.h" +#include "globalsettings.h" +#include "interfaces/bodypart.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +NodeHelper * NodeHelper::mSelf = 0; + +NodeHelper * NodeHelper::instance() +{ + if ( !mSelf ) + mSelf = new NodeHelper(); + return mSelf; +} + +NodeHelper::NodeHelper() +{ + mSelf = this; + //TODO(Andras) add methods to modify these prefixes + mReplySubjPrefixes << "Re\\s*:" << "Re\\[\\d+\\]:" << "Re\\d+:"; + mForwardSubjPrefixes << "Fwd:" << "FW:"; + + mLocalCodec = QTextCodec::codecForName( KGlobal::locale()->encoding() ); + + // In the case of Japan. Japanese locale name is "eucjp" but + // The Japanese mail systems normally used "iso-2022-jp" of locale name. + // We want to change locale name from eucjp to iso-2022-jp at KMail only. + + // (Introduction to i18n, 6.6 Limit of Locale technology): + // EUC-JP is the de-facto standard for UNIX systems, ISO 2022-JP + // is the standard for Internet, and Shift-JIS is the encoding + // for Windows and Macintosh. + if ( mLocalCodec->name().toLower() == "eucjp" +#if defined Q_WS_WIN || defined Q_WS_MACX + || mLocalCodec->name().toLower() == "shift-jis" // OK? +#endif + ) + { + mLocalCodec = QTextCodec::codecForName("jis7"); + // QTextCodec *cdc = QTextCodec::codecForName("jis7"); + // QTextCodec::setCodecForLocale(cdc); + // KGlobal::locale()->setEncoding(cdc->mibEnum()); + } + +} + +NodeHelper::~NodeHelper() +{ + mSelf = 0; +} + +void NodeHelper::setNodeProcessed(KMime::Content* node, bool recurse ) +{ + if ( !node ) + return; + mProcessedNodes.append( node ); + if ( recurse ) { + KMime::Content::List contents = node->contents(); + Q_FOREACH( KMime::Content *c, contents ) + { + setNodeProcessed( c, true ); + } + } +} + +void NodeHelper::setNodeUnprocessed(KMime::Content* node, bool recurse ) +{ + if ( !node ) + return; + mProcessedNodes.removeAll( node ); + if ( recurse ) { + KMime::Content::List contents = node->contents(); + Q_FOREACH( KMime::Content *c, contents ) + { + setNodeUnprocessed( c, true ); + } + } +} + +bool NodeHelper::nodeProcessed( KMime::Content* node ) const +{ + if ( !node ) + return true; + return mProcessedNodes.contains( node ); +} + +void NodeHelper::setNodeBeingProcessed( KMime::Content* node, bool process ) +{ + if ( !node ) + return; + + if ( process ) + mNodesUnderProcess.append( node ); + else + mNodesUnderProcess.removeAll( node ); +} + +bool NodeHelper::nodeBeingProcessed( KMime::Content* node ) +{ + if (!node) + return false; + + return mNodesUnderProcess.contains(node); +} + +void NodeHelper::clear() +{ + mProcessedNodes.clear(); + mEncryptionState.clear(); + mSignatureState.clear(); + qDeleteAll(mUnencryptedMessages); + mUnencryptedMessages.clear(); + mOverrideCodecs.clear(); + for ( QMap >::iterator + it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end(); + it != end; ++it ) { + clearBodyPartMemento( it.value() ); + } + mBodyPartMementoMap.clear(); + mDisplayEmbeddedNodes.clear(); +} + +void NodeHelper::clearBodyPartMemento(QMap bodyPartMementoMap) +{ + for ( QMap::iterator + it = bodyPartMementoMap.begin(), end = bodyPartMementoMap.end(); + it != end; ++it ) { + delete it.value(); + } + bodyPartMementoMap.clear(); +} + + +void NodeHelper::setEncryptionState( KMime::Content* node, const KMMsgEncryptionState state ) +{ + mEncryptionState[node] = state; +} + +KMMsgEncryptionState NodeHelper::encryptionState( KMime::Content *node ) const +{ + if ( mEncryptionState.contains( node ) ) + return mEncryptionState[node]; + + return KMMsgNotEncrypted; +} + +void NodeHelper::setSignatureState( KMime::Content* node, const KMMsgSignatureState state ) +{ + mSignatureState[node] = state; +} + +KMMsgSignatureState NodeHelper::signatureState( KMime::Content *node ) const +{ + if ( mSignatureState.contains( node ) ) + return mSignatureState[node]; + + return KMMsgNotSigned; +} + + +QString NodeHelper::writeNodeToTempFile(KMime::Content* node) +{ + // If the message part is already written to a file, no point in doing it again. + // This function is called twice actually, once from the rendering of the attachment + // in the body and once for the header. + KUrl existingFileName = tempFileUrlFromNode( node ); + if ( !existingFileName.isEmpty() ) { + return existingFileName.toLocalFile(); + } + + QString fileName = NodeHelper::fileName( node ); + + QString fname = createTempDir( node->index().toString() ); + if ( fname.isEmpty() ) + return QString(); + + // strip off a leading path + int slashPos = fileName.lastIndexOf( '/' ); + if( -1 != slashPos ) + fileName = fileName.mid( slashPos + 1 ); + if( fileName.isEmpty() ) + fileName = "unnamed"; + fname += '/' + fileName; + + kDebug() << "Create temp file: " << fname; + + QByteArray data = node->decodedContent(); + if ( node->contentType()->isText() && data.size() > 0 ) { + // convert CRLF to LF before writing text attachments to disk + data = KMime::CRLFtoLF( data ); + } + if( !KPIMUtils::kByteArrayToFile( data, fname, false, false, false ) ) + return QString(); + + mTempFiles.append( fname ); + // make file read-only so that nobody gets the impression that he might + // edit attached files (cf. bug #52813) + ::chmod( QFile::encodeName( fname ), S_IRUSR ); + + return fname; +} + + + +KUrl NodeHelper::tempFileUrlFromNode( const KMime::Content *node ) +{ + if (!node) + return KUrl(); + + QString index = node->index().toString(); + + foreach ( const QString &path, mTempFiles ) { + int right = path.lastIndexOf( '/' ); + int left = path.lastIndexOf( ".index.", right ); + if (left != -1) + left += 7; + + QString storedIndex = path.mid( left + 1, right - left - 1 ); + if ( left != -1 && storedIndex == index ) + return KUrl( path ); + } + return KUrl(); +} + + +QString NodeHelper::createTempDir( const QString ¶m ) +{ + KTemporaryFile *tempFile = new KTemporaryFile(); + tempFile->setSuffix( ".index." + param ); + tempFile->open(); + QString fname = tempFile->fileName(); + delete tempFile; + + if ( ::access( QFile::encodeName( fname ), W_OK ) != 0 ) { + // Not there or not writable + if( KDE_mkdir( QFile::encodeName( fname ), 0 ) != 0 || + ::chmod( QFile::encodeName( fname ), S_IRWXU ) != 0 ) { + return QString(); //failed create + } + } + + Q_ASSERT( !fname.isNull() ); + + mTempDirs.append( fname ); + return fname; +} + + +void NodeHelper::removeTempFiles() +{ + for (QStringList::Iterator it = mTempFiles.begin(); it != mTempFiles.end(); + ++it) + { + QFile::remove(*it); + } + mTempFiles.clear(); + for (QStringList::Iterator it = mTempDirs.begin(); it != mTempDirs.end(); + it++) + { + QDir(*it).rmdir(*it); + } + mTempDirs.clear(); +} + +void NodeHelper::addTempFile( const QString& file ) +{ + mTempFiles.append( file ); +} + + +KMime::Content *NodeHelper::firstChild( const KMime::Content* node ) +{ + if ( !node ) + return 0; + + KMime::Content *child = 0; + if ( !node->contents().isEmpty() ) + child = node->contents().at(0); + + return child; +} + +KMime::Content *NodeHelper::nextSibling( const KMime::Content* node ) +{ + if ( !node ) + return 0; + + KMime::Content *next = 0; + KMime::Content *parent = node->parent(); + if ( parent ) { + KMime::Content::List contents = parent->contents(); + int index = contents.indexOf( const_cast(node) ) + 1; + if ( index < contents.size() ) //next on the same level + next = contents.at( index ); + } + + return next; +} + +KMMsgEncryptionState NodeHelper::overallEncryptionState( KMime::Content *node ) const +{ + KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown; + if ( !node ) + return myState; + + if( encryptionState( node ) == KMMsgNotEncrypted ) { + // NOTE: children are tested ONLY when parent is not encrypted + KMime::Content *child = firstChild( node ); + if ( child ) + myState = overallEncryptionState( child ); + else + myState = KMMsgNotEncrypted; + } + else { // part is partially or fully encrypted + myState = encryptionState( node ); + } + // siblings are tested always + KMime::Content * next = nextSibling( node ); + if( next ) { + KMMsgEncryptionState otherState = overallEncryptionState( next ); + switch( otherState ) { + case KMMsgEncryptionStateUnknown: + break; + case KMMsgNotEncrypted: + if( myState == KMMsgFullyEncrypted ) + myState = KMMsgPartiallyEncrypted; + else if( myState != KMMsgPartiallyEncrypted ) + myState = KMMsgNotEncrypted; + break; + case KMMsgPartiallyEncrypted: + myState = KMMsgPartiallyEncrypted; + break; + case KMMsgFullyEncrypted: + if( myState != KMMsgFullyEncrypted ) + myState = KMMsgPartiallyEncrypted; + break; + case KMMsgEncryptionProblematic: + break; + } + } + +//kDebug() <<"\n\n KMMsgEncryptionState:" << myState; + + return myState; +} + + +KMMsgSignatureState NodeHelper::overallSignatureState( KMime::Content* node ) const +{ + KMMsgSignatureState myState = KMMsgSignatureStateUnknown; + if ( !node ) + return myState; + + if( signatureState( node ) == KMMsgNotSigned ) { + // children are tested ONLY when parent is not signed + KMime::Content* child = firstChild( node ); + if( child ) + myState = overallSignatureState( child ); + else + myState = KMMsgNotSigned; + } + else { // part is partially or fully signed + myState = signatureState( node ); + } + // siblings are tested always + KMime::Content *next = nextSibling( node ); + if( next ) { + KMMsgSignatureState otherState = overallSignatureState( next ); + switch( otherState ) { + case KMMsgSignatureStateUnknown: + break; + case KMMsgNotSigned: + if( myState == KMMsgFullySigned ) + myState = KMMsgPartiallySigned; + else if( myState != KMMsgPartiallySigned ) + myState = KMMsgNotSigned; + break; + case KMMsgPartiallySigned: + myState = KMMsgPartiallySigned; + break; + case KMMsgFullySigned: + if( myState != KMMsgFullySigned ) + myState = KMMsgPartiallySigned; + break; + case KMMsgSignatureProblematic: + break; + } + } + +//kDebug() <<"\n\n KMMsgSignatureState:" << myState; + + return myState; +} + +QString NodeHelper::iconName( KMime::Content *node, int size ) const +{ + if ( !node ) + return QString(); + + QByteArray mimeType = node->contentType()->mimeType(); + kAsciiToLower( mimeType.data() ); + + QString fileName; + KMimeType::Ptr mime = KMimeType::mimeType( mimeType, KMimeType::ResolveAliases ); + if (mime) { + fileName = mime->iconName(); + } else { + kWarning() <<"unknown mimetype" << mimeType; + } + + if ( fileName.isEmpty() ) + { + fileName = node->contentDisposition()->filename(); + if ( fileName.isEmpty() ) fileName = node->contentType()->name(); + if ( !fileName.isEmpty() ) + { + fileName = KMimeType::findByPath( "/tmp/"+fileName, 0, true )->iconName(); + } + } + + return MessageViewer::IconNameCache::instance()->iconPath( fileName, size ); +} + +void NodeHelper::magicSetType( KMime::Content* node, bool aAutoDecode ) +{ + const QByteArray body = ( aAutoDecode ) ? node->decodedContent() : node->body() ; + KMimeType::Ptr mime = KMimeType::findByContent( body ); + + QString mimetype = mime->name(); + node->contentType()->setMimeType( mimetype.toLatin1() ); +} + +// static +QString NodeHelper::replacePrefixes( const QString& str, + const QStringList& prefixRegExps, + bool replace, + const QString& newPrefix ) +{ + bool recognized = false; + // construct a big regexp that + // 1. is anchored to the beginning of str (sans whitespace) + // 2. matches at least one of the part regexps in prefixRegExps + QString bigRegExp = QString::fromLatin1("^(?:\\s+|(?:%1))+\\s*") + .arg( prefixRegExps.join(")|(?:") ); + QRegExp rx( bigRegExp, Qt::CaseInsensitive ); + if ( !rx.isValid() ) { + kWarning() << "bigRegExp = \"" + << bigRegExp << "\"\n" + << "prefix regexp is invalid!"; + // try good ole Re/Fwd: + recognized = str.startsWith( newPrefix ); + } else { // valid rx + QString tmp = str; + if ( rx.indexIn( tmp ) == 0 ) { + recognized = true; + if ( replace ) + return tmp.replace( 0, rx.matchedLength(), newPrefix + ' ' ); + } + } + if ( !recognized ) + return newPrefix + ' ' + str; + else + return str; +} + +QString NodeHelper::cleanSubject( KMime::Message* message ) const +{ + return cleanSubject( message, mReplySubjPrefixes + mForwardSubjPrefixes, + true, QString() ).trimmed(); +} + +QString NodeHelper::cleanSubject( KMime::Message* message, const QStringList & prefixRegExps, + bool replace, + const QString & newPrefix ) const +{ + return NodeHelper::replacePrefixes( message->subject()->asUnicodeString(), prefixRegExps, replace, + newPrefix ); +} + +void NodeHelper::attachUnencryptedMessage( KMime::Message* message, KMime::Message* unencrypted) +{ + if ( !message ) + return; + + if ( mUnencryptedMessages.contains( message ) ) + delete mUnencryptedMessages[message]; + mUnencryptedMessages[message] = unencrypted; +} + +void NodeHelper::setOverrideCodec( KMime::Content* node, const QTextCodec* codec ) +{ + if (! node ) + return; + + mOverrideCodecs[node] = codec; +} + +const QTextCodec * NodeHelper::codec( KMime::Content* node ) +{ + if (! node ) + return mLocalCodec; + + const QTextCodec *c = mOverrideCodecs[node]; + if ( !c ) { + // no override-codec set for this message, try the CT charset parameter: + c = codecForName( node->contentType()->charset() ); + } + if ( !c ) { + // Ok, no override and nothing in the message, let's use the fallback + // the user configured + c = codecForName( GlobalSettings::self()->fallbackCharacterEncoding().toLatin1() ); + } + if ( !c ) { + // no charset means us-ascii (RFC 2045), so using local encoding should + // be okay + c = mLocalCodec; + } + return c; +} + +const QTextCodec* NodeHelper::codecForName(const QByteArray& _str) +{ + if (_str.isEmpty()) + return 0; + QByteArray codec = _str; + kAsciiToLower(codec.data()); + return KGlobal::charsets()->codecForName(codec); +} + +QByteArray NodeHelper::path(const KMime::Content* node) +{ + if ( !node->parent() ) { + return QByteArray( ":" ); + } + const KMime::Content *p = node->parent(); + + // count number of siblings with the same type as us: + int nth = 0; + for ( KMime::Content *c = NodeHelper::firstChild(p); c != node; c = NodeHelper::nextSibling(c) ) { + if ( c->contentType()->mediaType() == const_cast(node)->contentType()->mediaType() && c->contentType()->subType() == const_cast(node)->contentType()->subType() ) { + ++nth; + } + } + QString subpath; + return NodeHelper::path(p) + subpath.sprintf( ":%X/%X[%X]", const_cast(node)->contentType()->mediaType(), const_cast(node)->contentType()->subType(), nth ).toLocal8Bit(); +} + +QString NodeHelper::fileName(const KMime::Content* node) +{ + QString name = const_cast(node)->contentDisposition()->filename(); + if ( name.isEmpty() ) + name = const_cast(node)->contentType()->name();; + + name = name.trimmed(); + return name; +} + +//FIXME(Andras) review it (by Marc?) to see if I got it right. This is supposed to be the partNode::internalBodyPartMemento replacement +MessageViewer::Interface::BodyPartMemento *NodeHelper::bodyPartMemento( KMime::Content *node, + const QByteArray &which ) const +{ + if ( !mBodyPartMementoMap.contains( node ) ) + return 0; + const QMap::const_iterator it = + mBodyPartMementoMap[node].find( which.toLower() ); + return it != mBodyPartMementoMap[node].end() ? it.value() : 0 ; +} + + //FIXME(Andras) review it (by Marc?) to see if I got it right. This is supposed to be the partNode::internalSetBodyPartMemento replacement +void NodeHelper::setBodyPartMemento( KMime::Content* node, const QByteArray &which, MessageViewer::Interface::BodyPartMemento *memento ) +{ + const QMap::iterator it = + mBodyPartMementoMap[node].lowerBound( which.toLower() ); + + if ( it != mBodyPartMementoMap[node].end() && it.key() == which.toLower() ) { + delete it.value(); + if ( memento ) { + it.value() = memento; + } else { + mBodyPartMementoMap[node].erase( it ); + } + } else { + mBodyPartMementoMap[node].insert( which.toLower(), memento ); + } +} + +bool NodeHelper::isNodeDisplayedEmbedded( KMime::Content* node ) const +{ + return mDisplayEmbeddedNodes.contains( node ); +} + +void NodeHelper::setNodeDisplayedEmbedded( KMime::Content* node, bool displayedEmbedded ) +{ + if ( displayedEmbedded ) + mDisplayEmbeddedNodes.insert( node ); + else + mDisplayEmbeddedNodes.remove( node ); +} + +QString NodeHelper::asHREF( const KMime::Content* node, const QString &place ) +{ + if ( !node ) + return QString(); + else + return QString( "attachment:%1?place=%2" ).arg( node->index().toString() ).arg( place ); +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/nodehelper.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/nodehelper.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/nodehelper.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/nodehelper.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,207 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#ifndef _MESSAGEVIEWER_NODEHELPER_H +#define _MESSAGEVIEWER_NODEHELPER_H + +#include +#include +#include +#include + +class KUrl; +class QTextCodec; + +namespace KMime { + class Content; + class Message; +} + +namespace MessageViewer { + namespace Interface { + class BodyPartMemento; + } +} + +/** + @author Andras Mantia +*/ + +/** Flags for the encryption state. */ +typedef enum +{ + KMMsgEncryptionStateUnknown=' ', + KMMsgNotEncrypted='N', + KMMsgPartiallyEncrypted='P', + KMMsgFullyEncrypted='F', + KMMsgEncryptionProblematic='X' +} KMMsgEncryptionState; + +/** Flags for the signature state. */ +typedef enum +{ + KMMsgSignatureStateUnknown=' ', + KMMsgNotSigned='N', + KMMsgPartiallySigned='P', + KMMsgFullySigned='F', + KMMsgSignatureProblematic='X' +} KMMsgSignatureState; + +class NodeHelper{ +public: + static NodeHelper * instance(); + + ~NodeHelper(); + + void setNodeBeingProcessed( KMime::Content* node, bool processing ); + bool nodeBeingProcessed( KMime::Content* node ); + void setNodeProcessed( KMime::Content* node, bool recurse ); + void setNodeUnprocessed( KMime::Content* node, bool recurse ); + bool nodeProcessed( KMime::Content* node ) const; + void clear(); + + void setEncryptionState( KMime::Content* node, const KMMsgEncryptionState state ); + KMMsgEncryptionState encryptionState( KMime::Content *node ) const; + + void setSignatureState( KMime::Content* node, const KMMsgSignatureState state ); + KMMsgSignatureState signatureState( KMime::Content *node ) const; + + KMMsgSignatureState overallSignatureState( KMime::Content* node ) const; + KMMsgEncryptionState overallEncryptionState( KMime::Content *node ) const; + + + QString iconName( KMime::Content *node, int size = KIconLoader::Desktop ) const; + /** Set the 'Content-Type' by mime-magic from the contents of the body. + If autoDecode is true the decoded body will be used for mime type + determination (this does not change the body itself). */ + void magicSetType( KMime::Content *node, bool autoDecode=true ); + + + /** Return this mails subject, with all "forward" and "reply" + prefixes removed */ + QString cleanSubject( KMime::Message* message ) const; + + /** Attach an unencrypted message to an encrypted one */ + void attachUnencryptedMessage( KMime::Message* message, KMime::Message* unencrypted); + + /** Get a QTextCodec suitable for this message part */ + const QTextCodec * codec( KMime::Content* node ); + + /** Set the charset the user selected for the message to display */ + void setOverrideCodec( KMime::Content* node, const QTextCodec* codec ); + + const QTextCodec * localCodec() const { return mLocalCodec;} + + MessageViewer::Interface::BodyPartMemento *bodyPartMemento( KMime::Content* node, const QByteArray &which ) const; + + void setBodyPartMemento( KMime::Content* node, const QByteArray &which, MessageViewer::Interface::BodyPartMemento *memento ); + + // A flag to remember if the node was embedded. This is useful for attachment nodes, the reader + // needs to know if they were displayed inline or not. + bool isNodeDisplayedEmbedded( KMime::Content* node ) const; + void setNodeDisplayedEmbedded( KMime::Content* node, bool displayedEmbedded ); + + /** Writes the given message part to a temporary file and returns the + name of this file or QString() if writing failed. + */ + QString writeNodeToTempFile( KMime::Content* node ); + + /** Returns the temporary file path and name where this node was saved, or an empty url + * if it wasn't saved yet with writeNodeToTempFile() + */ + KUrl tempFileUrlFromNode( const KMime::Content *node ); + + /** + Creates a temporary dir for saving attachments, etc. + Will be automatically deleted when another message is viewed. + @param param Optional part of the directory name. + */ + QString createTempDir( const QString ¶m = QString() ); + + /** Cleanup the attachment temp files */ + void removeTempFiles(); + + /** Add a file to the list of managed temporary files */ + void addTempFile( const QString& file ); + + //static methods + static KMime::Content *nextSibling( const KMime::Content* node ); + + static KMime::Content *firstChild( const KMime::Content* node ); + + /** Check for prefixes @p prefixRegExps in @p str. If none + is found, @p newPrefix + ' ' is prepended to @p str and the + resulting string is returned. If @p replace is true, any + sequence of whitespace-delimited prefixes at the beginning of + @p str is replaced by @p newPrefix. + **/ + static QString replacePrefixes( const QString& str, + const QStringList& prefixRegExps, + bool replace, + const QString& newPrefix ); + + /** Return a QTextCodec for the specified charset. + * This function is a bit more tolerant, than QTextCodec::codecForName + **/ + static const QTextCodec* codecForName(const QByteArray& _str); + + static QByteArray path(const KMime::Content* node); + + /** Returns a usable filename for a node, that can be the filename from the + * content disposition header, or if that one is empty, the name from the + * content type header. */ + static QString fileName(const KMime::Content* node); + + // Get a href in the form attachment:?place=, used by ObjectTreeParser and + // UrlHandlerManager. + static QString asHREF( const KMime::Content* node, const QString &place ); + + +private: + NodeHelper(); + + /** Check for prefixes @p prefixRegExps in #subject(). If none + is found, @p newPrefix + ' ' is prepended to the subject and the + resulting string is returned. If @p replace is true, any + sequence of whitespace-delimited prefixes at the beginning of + #subject() is replaced by @p newPrefix + **/ + QString cleanSubject( KMime::Message* message, const QStringList& prefixRegExps, bool replace, + const QString& newPrefix ) const; + + void clearBodyPartMemento(QMap bodyPartMementoMap); + + static NodeHelper * mSelf; + + QList mProcessedNodes; + QList mNodesUnderProcess; + QMap mEncryptionState; + QMap mSignatureState; + QMap mUnencryptedMessages; + QSet mDisplayEmbeddedNodes; + QStringList mReplySubjPrefixes, mForwardSubjPrefixes; + QTextCodec *mLocalCodec; + QMap mOverrideCodecs; + QMap > mBodyPartMementoMap; + QStringList mTempFiles; + QStringList mTempDirs; +}; + + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeemptysource.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeemptysource.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeemptysource.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeemptysource.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,101 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#include "objecttreeemptysource.h" +#include "viewer_p.h" + +#include "attachmentstrategy.h" + +namespace MessageViewer { + +EmptySource::EmptySource() : ObjectTreeSourceIf() +{ +} + +EmptySource::~EmptySource() +{ +} + +bool EmptySource::htmlMail() +{ + return false; +} + +bool EmptySource::decryptMessage() +{ + return true; //by default decrypt the messages +} + +bool EmptySource::htmlLoadExternal() +{ + return false; +} + +bool EmptySource::showSignatureDetails() +{ + return false; +} + +void EmptySource::setHtmlMode( bool mode ) +{ + Q_UNUSED( mode ); +} + +int EmptySource::levelQuote() +{ + return 1; +} + +const QTextCodec * EmptySource::overrideCodec() +{ + return 0; +} + +QString EmptySource::createMessageHeader( KMime::Message* message ) +{ + return QString(); //do nothing +} + +void EmptySource::emitNoDrag() +{ + //do nothing +} + +QObject *EmptySource::sourceObject() +{ + return 0; +} + +const AttachmentStrategy * EmptySource::attachmentStrategy() +{ + return AttachmentStrategy::smart(); +} + +HtmlWriter * EmptySource::htmlWriter() +{ + return 0; +} + +CSSHelper* EmptySource::cssHelper() +{ + return 0; +} + +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeemptysource.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeemptysource.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeemptysource.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeemptysource.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,51 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#ifndef MAILVIEWER_EMPTYSOURCE_H +#define MAILVIEWER_EMPTYSOURCE_H + +#include "objecttreesourceif.h" + +class QString; + +namespace MessageViewer { +/** An ObjectTreeSource that does not work on anything */ +class EmptySource : public ObjectTreeSourceIf { + public: + EmptySource( ); + ~EmptySource(); + bool htmlMail(); + bool decryptMessage(); + bool htmlLoadExternal(); + bool showSignatureDetails(); + void setHtmlMode( bool mode ); + int levelQuote(); + const QTextCodec * overrideCodec(); + QString createMessageHeader( KMime::Message* message ); + void emitNoDrag(); + const AttachmentStrategy * attachmentStrategy(); + HtmlWriter * htmlWriter(); + CSSHelper* cssHelper(); + QObject *sourceObject(); +}; + +} + +#endif + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeparser.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeparser.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeparser.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeparser.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,3289 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + objecttreeparser.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +// my header file +#include "objecttreeparser.h" +#include "objecttreeparser_p.h" +#include "objecttreesourceif.h" + +// other KMail headers +#include "viewer_p.h" +#include +#include "partmetadata.h" +#include "attachmentstrategy.h" +#include "interfaces/htmlwriter.h" +#include "htmlstatusbar.h" +#include "csshelper.h" +#include "bodypartformatter.h" +#include "bodypartformatterfactory.h" +#include "partnodebodypart.h" +#include "interfaces/bodypartformatter.h" +#include "globalsettings.h" +#include "util.h" +#include "global.h" +#include "kleojobexecutor.h" +#include "stringutil.h" +#include "nodehelper.h" +#include "iconnamecache.h" +#include "htmlquotecolorer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +using KPIMUtils::LinkLocator; + +#include +#include +#include + +// other KDE headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// other Qt headers +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// other headers +#include +#include +#include +#include +#include +// FIXME(Andras) port to akonadi #include "chiasmuskeyselector.h" + +#include + +using namespace MessageViewer; + +// A small class that eases temporary CryptPlugWrapper changes: +class ObjectTreeParser::CryptoProtocolSaver { + ObjectTreeParser * otp; + const Kleo::CryptoBackend::Protocol * protocol; +public: + CryptoProtocolSaver( ObjectTreeParser * _otp, const Kleo::CryptoBackend::Protocol* _w ) + : otp( _otp ), protocol( _otp ? _otp->cryptoProtocol() : 0 ) + { + if ( otp ) + otp->setCryptoProtocol( _w ); + } + + ~CryptoProtocolSaver() { + if ( otp ) + otp->setCryptoProtocol( protocol ); + } +}; + + +ObjectTreeParser::ObjectTreeParser( ObjectTreeSourceIf *source, + const Kleo::CryptoBackend::Protocol * protocol, + bool showOnlyOneMimePart, bool keepEncryptions, + bool includeSignatures, + const AttachmentStrategy * strategy, + HtmlWriter * htmlWriter, + CSSHelper * cssHelper ) + : mSource( source ), + mCryptoProtocol( protocol ), + mShowOnlyOneMimePart( showOnlyOneMimePart ), + mKeepEncryptions( keepEncryptions ), + mIncludeSignatures( includeSignatures ), + mHasPendingAsyncJobs( false ), + mAllowAsync( false ), + mAttachmentStrategy( strategy ), + mHtmlWriter( htmlWriter ), + mCSSHelper( cssHelper ) +{ + assert( source ); + if ( !attachmentStrategy() ) + mAttachmentStrategy = source->attachmentStrategy(); + if ( !this->htmlWriter() ) + mHtmlWriter = source->htmlWriter(); + if ( !this->cssHelper() ) + mCSSHelper = source->cssHelper(); +} + +ObjectTreeParser::ObjectTreeParser( const ObjectTreeParser & other ) + : mSource( other.mSource ), + mCryptoProtocol( other.cryptoProtocol() ), + mShowOnlyOneMimePart( other.showOnlyOneMimePart() ), + mKeepEncryptions( other.keepEncryptions() ), + mIncludeSignatures( other.includeSignatures() ), + mHasPendingAsyncJobs( other.hasPendingAsyncJobs() ), + mAllowAsync( other.allowAsync() ), + mAttachmentStrategy( other.attachmentStrategy() ), + mHtmlWriter( other.htmlWriter() ), + mCSSHelper( other.cssHelper() ) +{ + +} + +ObjectTreeParser::~ObjectTreeParser() {} + +void ObjectTreeParser::insertAndParseNewChildNode( KMime::Content& startNode, + const char* content, + const char* cntDesc, + bool append, bool addToTextualContent ) +{ + KMime::Content *newNode = new KMime::Content(); + newNode->setContent( content ); + newNode->parse(); +/*TODO (Andras) port it + if ( ( !myBody->Body().FirstBodyPart() || + myBody->body().length() == 0 ) && + startNode.dwPart() && + startNode.dwPart()->Body().Message() && + startNode.dwPart()->Body().Message()->Body().FirstBodyPart() ) + { + // if encapsulated imap messages are loaded the content-string is not complete + // so we need to keep the child dwparts + myBody = new DwBodyPart( *(startNode.dwPart()->Body().Message()) ); + } + */ + + if ( !newNode->head().isEmpty() ) { + newNode->contentDescription()->from7BitString( cntDesc ); + } + + startNode.addContent( newNode, !append ); + +/*TODO(Andras) check what should we do here: + newNode->buildObjectTree( false ); + + if ( startNode.mimePartTreeItem() ) { + newNode->fillMimePartTree( startNode.mimePartTreeItem(), 0, + QString(), QString(), QString(), 0, + append ); + }*/ + ObjectTreeParser otp( mSource, cryptoProtocol() ); + otp.parseObjectTree( newNode ); + if ( addToTextualContent ) { + mRawReplyString += otp.rawReplyString(); + mTextualContent += otp.textualContent(); + if ( !otp.textualContentCharset().isEmpty() ) + mTextualContentCharset = otp.textualContentCharset(); + } +} + + +//----------------------------------------------------------------------------- + +void ObjectTreeParser::parseObjectTree( KMime::Content * node ) { + + if ( !node ) + return; + + // reset pending async jobs state (we'll rediscover pending jobs as we go) + mHasPendingAsyncJobs = false; + + // reset "processed" flags for... + if ( showOnlyOneMimePart() ) { + // ... this node and all descendants + NodeHelper::instance()->setNodeUnprocessed( node, false ); + if ( KMime::Content* child = NodeHelper::firstChild( node ) ) + NodeHelper::instance()->setNodeUnprocessed( node, true ); + } else if ( !node->parent() ) { + // ...this node and all it's siblings and descendants + NodeHelper::instance()->setNodeUnprocessed( node, true ); + } + + // Make sure the whole content is relative, so that nothing is painted over the header + // if a malicious message uses absolute positioning. + bool isRoot = node->isTopLevel(); + if ( isRoot && mHtmlWriter ) + htmlWriter()->queue( "
\n" ); + + KMime::Content::List contents = node->contents(); + contents.prepend(node); //the toplevel node needs to parsed as well + Q_FOREACH(KMime::Content *c, contents) + { + if ( NodeHelper::instance()->nodeProcessed( c ) ) + continue; + ProcessResult processResult; + + if ( mHtmlWriter ) + htmlWriter()->queue( QString::fromLatin1("").arg( node->indexForContent(c).toString() ) ); + if ( const Interface::BodyPartFormatter * formatter + = BodyPartFormatterFactory::instance()->createFor( c->contentType()->mediaType(), c->contentType()->subType() ) ) { + PartNodeBodyPart part( c, codecFor( c ) ); + // Set the default display strategy for this body part relying on the + // identity of Interface::BodyPart::Display and AttachmentStrategy::Display + part.setDefaultDisplay( (Interface::BodyPart::Display) attachmentStrategy()->defaultDisplay( c ) ); + + writeAttachmentMarkHeader( c ); + NodeHelper::instance()->setNodeDisplayedEmbedded( c, true ); + const Interface::BodyPartFormatter::Result result = formatter->format( &part, htmlWriter() ); + writeAttachmentMarkFooter(); + + switch ( result ) { + case Interface::BodyPartFormatter::AsIcon: + processResult.setNeverDisplayInline( true ); + // fall through: + case Interface::BodyPartFormatter::Failed: + defaultHandling( node, processResult ); + break; + case Interface::BodyPartFormatter::Ok: + case Interface::BodyPartFormatter::NeedContent: + // FIXME: incomplete content handling + ; + } + } else { + const BodyPartFormatter * bpf + = BodyPartFormatter::createFor( c->contentType()->mediaType(), c->contentType()->subType() ); + kFatal( !bpf, 5006 ) <<"THIS SHOULD NO LONGER HAPPEN (" + << c->contentType()->mediaType() << '/' << c->contentType()->subType() << ')'; + writeAttachmentMarkHeader( c ); + if ( bpf && !bpf->process( this, c, processResult ) ) + defaultHandling( c, processResult ); + writeAttachmentMarkFooter(); + } + NodeHelper::instance()->instance()->setNodeProcessed( c, false); + + // adjust signed/encrypted flags if inline PGP was found + processResult.adjustCryptoStatesOfNode( node ); + + if ( showOnlyOneMimePart() ) + break; + } + + if ( isRoot && mHtmlWriter ) + htmlWriter()->queue( "
\n" ); +} + +void ObjectTreeParser::defaultHandling( KMime::Content * node, ProcessResult & result ) { + // ### (mmutz) default handling should go into the respective + // ### bodypartformatters. + if ( !mHtmlWriter ) + return; + + // always show images in multipart/related when showing in html, not with an additional icon + if ( result.isImage() && node->parent() && + node->parent()->contentType()->subType() == "related" && mSource->htmlMail() && !showOnlyOneMimePart() ) { + QString fileName = NodeHelper::instance()->writeNodeToTempFile( node ); + QString href = "file:" + KUrl::toPercentEncoding( fileName ); + QByteArray cid = node->contentID()->as7BitString(false); + if ( cid.startsWith('<') ) + cid = cid.mid(1); + if ( cid.endsWith('>') ) + cid = cid.left( cid.length() - 1 ); + htmlWriter()->embedPart( cid, href ); + return; + } + + if ( attachmentStrategy() == AttachmentStrategy::hidden() && + !showOnlyOneMimePart() && + node->parent() /* message is not an attachment */ ) + return; + + bool asIcon = true; + if ( !result.neverDisplayInline() ) + if ( const AttachmentStrategy * as = attachmentStrategy() ) + asIcon = as->defaultDisplay( node ) == AttachmentStrategy::AsIcon; + + // Show it inline if showOnlyOneMimePart(), which means the user clicked the image + // in the message structure viewer manually, and therefore wants to see the full image + if ( result.isImage() && showOnlyOneMimePart() && !result.neverDisplayInline() ) + asIcon = false; + + // neither image nor text -> show as icon + if ( !result.isImage() + && !node->contentType()->isText() ) + asIcon = true; + +/*FIXME(Andras) port it + // if the image is not complete do not try to show it inline + if ( result.isImage() && !node->msgPart().isComplete() ) + asIcon = true; + */ + + if ( asIcon ) { + if ( attachmentStrategy() != AttachmentStrategy::hidden() + || showOnlyOneMimePart() ) + // Write the node as icon only + writePartIcon( node ); + } else if ( result.isImage() ) { + // Embed the image + NodeHelper::instance()->setNodeDisplayedEmbedded( node, true ); + writePartIcon( node, true ); + } else { + NodeHelper::instance()->setNodeDisplayedEmbedded( node, true ); + KMime::Message *topLevel = dynamic_cast(node->topLevel()); + writeBodyString( node->decodedContent(), + topLevel ? topLevel->from()->asUnicodeString() : QString(), + codecFor( node ), result, false ); + } + // end of ### +} + +void ProcessResult::adjustCryptoStatesOfNode( KMime::Content * node ) const { + if ( ( inlineSignatureState() != KMMsgNotSigned ) || + ( inlineEncryptionState() != KMMsgNotEncrypted ) ) { + NodeHelper::instance()->setSignatureState( node, inlineSignatureState() ); + NodeHelper::instance()->setEncryptionState( node, inlineEncryptionState() ); + } +} + +////////////////// +////////////////// +////////////////// + +static int signatureToStatus( const GpgME::Signature &sig ) +{ + switch ( sig.status().code() ) { + case GPG_ERR_NO_ERROR: + return GPGME_SIG_STAT_GOOD; + case GPG_ERR_BAD_SIGNATURE: + return GPGME_SIG_STAT_BAD; + case GPG_ERR_NO_PUBKEY: + return GPGME_SIG_STAT_NOKEY; + case GPG_ERR_NO_DATA: + return GPGME_SIG_STAT_NOSIG; + case GPG_ERR_SIG_EXPIRED: + return GPGME_SIG_STAT_GOOD_EXP; + case GPG_ERR_KEY_EXPIRED: + return GPGME_SIG_STAT_GOOD_EXPKEY; + default: + return GPGME_SIG_STAT_ERROR; + } +} + +bool ObjectTreeParser::writeOpaqueOrMultipartSignedData( KMime::Content* data, + KMime::Content& sign, + const QString& fromAddress, + bool doCheck, + QByteArray* cleartextData, + const std::vector & paramSignatures, + bool hideErrors ) +{ + kDebug() << "DECRYPT" << data; + bool bIsOpaqueSigned = false; + enum { NO_PLUGIN, NOT_INITIALIZED, CANT_VERIFY_SIGNATURES } + cryptPlugError = NO_PLUGIN; + + const Kleo::CryptoBackend::Protocol* cryptProto = cryptoProtocol(); + + QString cryptPlugLibName; + QString cryptPlugDisplayName; + if ( cryptProto ) { + cryptPlugLibName = cryptProto->name(); + cryptPlugDisplayName = cryptProto->displayName(); + } + +#ifdef DEBUG_SIGNATURE +#ifndef NDEBUG + if ( !doCheck ) + kDebug() << "showing OpenPGP (Encrypted+Signed) data"; + else + if ( data ) + kDebug() << "processing Multipart Signed data"; + else + kDebug() << "processing Opaque Signed data"; +#endif + + if ( doCheck && cryptProto ) { + kDebug() << "going to call CRYPTPLUG" << cryptPlugLibName; + } +#endif + + QByteArray cleartext; + QByteArray signaturetext; + + if ( doCheck && cryptProto ) { + if ( data ) { + cleartext = data->head() + "\n" + data->body(); +#ifdef DEBUG_SIGNATURE + kDebug() << "ClearText : " << cleartext; + + dumpToFile( "dat_01_reader_signedtext_before_canonicalization", + cleartext.data(), cleartext.length() ); + + // replace simple LFs by CRLSs + // according to RfC 2633, 3.1.1 Canonicalization + kDebug() <<"Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)"; +#endif + cleartext = KMime::LFtoCRLF( cleartext ); +#ifdef DEBUG_SIGNATURE + kDebug() <<" done."; +#endif +} + + dumpToFile( "dat_02_reader_signedtext_after_canonicalization", + cleartext.data(), cleartext.length() ); + + signaturetext = sign.body(); + dumpToFile( "dat_03_reader.sig", signaturetext.data(), + signaturetext.size() ); + } + + std::vector signatures; + if ( !doCheck ) + signatures = paramSignatures; + + PartMetaData messagePart; + messagePart.isSigned = true; + messagePart.technicalProblem = ( cryptProto == 0 ); + messagePart.isGoodSignature = false; + messagePart.isEncrypted = false; + messagePart.isDecryptable = false; + messagePart.keyTrust = Kpgp::KPGP_VALIDITY_UNKNOWN; + messagePart.status = i18n("Wrong Crypto Plug-In."); + messagePart.status_code = GPGME_SIG_STAT_NONE; + + GpgME::Key key; + + if ( doCheck && cryptProto ) { + GpgME::VerificationResult result; + if ( data ) { // detached + const VerifyDetachedBodyPartMemento * m + = dynamic_cast( NodeHelper::instance()->bodyPartMemento( &sign, "verifydetached" ) ); + if ( !m ) { + Kleo::VerifyDetachedJob * job = cryptProto->verifyDetachedJob(); + if ( !job ) { + cryptPlugError = CANT_VERIFY_SIGNATURES; + // PENDING(marc) cryptProto = 0 here? + } else { + QByteArray plainData = cleartext; + VerifyDetachedBodyPartMemento * newM + = new VerifyDetachedBodyPartMemento( job, cryptProto->keyListJob(), signaturetext, plainData ); + if ( allowAsync() ) { + QObject::connect(newM, SIGNAL(update(MessageViewer::Viewer::UpdateMode)), mSource->sourceObject(), SLOT(update(MessageViewer::Viewer::UpdateMode))); + if ( newM->start() ) { + messagePart.inProgress = true; + mHasPendingAsyncJobs = true; + } else { + m = newM; + } + } else { + newM->exec(); + m = newM; + } + NodeHelper::instance()->setBodyPartMemento( &sign, "verifydetached", newM ); + } + } else if ( m->isRunning() ) { + messagePart.inProgress = true; + mHasPendingAsyncJobs = true; + m = 0; + } + + if ( m ) { + result = m->verifyResult(); + messagePart.auditLogError = m->auditLogError(); + messagePart.auditLog = m->auditLogAsHtml(); + key = m->signingKey(); + } + } else { // opaque + const VerifyOpaqueBodyPartMemento * m + = dynamic_cast( NodeHelper::instance()->bodyPartMemento( &sign, "verifyopaque" ) ); + if ( !m ) { + Kleo::VerifyOpaqueJob * job = cryptProto->verifyOpaqueJob(); + if ( !job ) { + cryptPlugError = CANT_VERIFY_SIGNATURES; + // PENDING(marc) cryptProto = 0 here? + } else { + VerifyOpaqueBodyPartMemento * newM + = new VerifyOpaqueBodyPartMemento( job, cryptProto->keyListJob(), signaturetext ); + if ( allowAsync() ) { + QObject::connect(newM, SIGNAL(update(MessageViewer::Viewer::UpdateMode)), mSource->sourceObject(), SLOT(update(MessageViewer::Viewer::UpdateMode))); + if ( newM->start() ) { + messagePart.inProgress = true; + mHasPendingAsyncJobs = true; + } else { + m = newM; + } + } else { + newM->exec(); + m = newM; + } + NodeHelper::instance()->setBodyPartMemento( &sign, "verifyopaque", newM ); + } + } else if ( m->isRunning() ) { + messagePart.inProgress = true; + mHasPendingAsyncJobs = true; + m = 0; + } + + if ( m ) { + result = m->verifyResult(); + cleartext = m->plainText(); + messagePart.auditLogError = m->auditLogError(); + messagePart.auditLog = m->auditLogAsHtml(); + key = m->signingKey(); + } + } + std::stringstream ss; + ss << result; +#ifdef DEBUG_SIGNATURE + kDebug() << ss.str().c_str(); +#endif + signatures = result.signatures(); + } + else + messagePart.auditLogError = GpgME::Error( GPG_ERR_NOT_IMPLEMENTED ); + +#ifdef DEBUG_SIGNATURE + if ( doCheck ) + kDebug() << "returned from CRYPTPLUG"; +#endif + + // ### only one signature supported + if ( !signatures.empty() ) { +#ifdef DEBUG_SIGNATURE + kDebug() << "\nFound signature"; +#endif + GpgME::Signature signature = signatures.front(); + + messagePart.status_code = signatureToStatus( signature ); + messagePart.status = QString::fromLocal8Bit( signature.status().asString() ); + for ( uint i = 1; i < signatures.size(); ++i ) { + if ( signatureToStatus( signatures[i] ) != messagePart.status_code ) { + messagePart.status_code = GPGME_SIG_STAT_DIFF; + messagePart.status = i18n("Different results for signatures"); + } + } + if ( messagePart.status_code & GPGME_SIG_STAT_GOOD ) + messagePart.isGoodSignature = true; + + // save extended signature status flags + messagePart.sigSummary = signature.summary(); + + if ( key.keyID() ) + messagePart.keyId = key.keyID(); + if ( messagePart.keyId.isEmpty() ) + messagePart.keyId = signature.fingerprint(); + // ### Ugh. We depend on two enums being in sync: + messagePart.keyTrust = (Kpgp::Validity)signature.validity(); + if ( key.numUserIDs() > 0 && key.userID( 0 ).id() ) + messagePart.signer = Kleo::DN( key.userID( 0 ).id() ).prettyDN(); + for ( uint iMail = 0; iMail < key.numUserIDs(); ++iMail ) { + // The following if /should/ always result in TRUE but we + // won't trust implicitely the plugin that gave us these data. + if ( key.userID( iMail ).email() ) { + QString email = QString::fromUtf8( key.userID( iMail ).email() ); + // ### work around gpgme 0.3.x / cryptplug bug where the + // ### email addresses are specified as angle-addr, not addr-spec: + if ( email.startsWith( '<' ) && email.endsWith( '>' ) ) + email = email.mid( 1, email.length() - 2 ); + if ( !email.isEmpty() ) + messagePart.signerMailAddresses.append( email ); + } + } + + if ( signature.creationTime() ) + messagePart.creationTime.setTime_t( signature.creationTime() ); + else + messagePart.creationTime = QDateTime(); + if ( messagePart.signer.isEmpty() ) { + if ( key.numUserIDs() > 0 && key.userID( 0 ).name() ) + messagePart.signer = Kleo::DN( key.userID( 0 ).name() ).prettyDN(); + if ( !messagePart.signerMailAddresses.empty() ) { + if ( messagePart.signer.isEmpty() ) + messagePart.signer = messagePart.signerMailAddresses.front(); + else + messagePart.signer += " <" + messagePart.signerMailAddresses.front() + '>'; + } + } +#ifdef DEBUG_SIGNATURE + kDebug() << "\n key id:" << messagePart.keyId + << "\n key trust:" << messagePart.keyTrust + << "\n signer:" << messagePart.signer; +#endif + } else { + messagePart.creationTime = QDateTime(); + } + + if ( !doCheck || !data ){ + if ( cleartextData || !cleartext.isEmpty() ) { + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatHeader( messagePart, + cryptProto, + fromAddress ) ); + bIsOpaqueSigned = true; + + CryptoProtocolSaver cpws( this, cryptProto ); + insertAndParseNewChildNode( sign, doCheck ? cleartext.data() : cleartextData->data(), + "opaqued signed data" ); + + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); + + } + else if ( !hideErrors ) { + QString txt; + txt = "

"; + txt.append( i18n( "The crypto engine returned no cleartext data." ) ); + txt.append( "

" ); + txt.append( "
 
" ); + txt.append( i18n( "Status: " ) ); + if ( !messagePart.status.isEmpty() ) { + txt.append( "" ); + txt.append( messagePart.status ); + txt.append( "" ); + } + else + txt.append( i18nc("Status of message unknown.","(unknown)") ); + if ( mHtmlWriter ) + htmlWriter()->queue(txt); + } + } + else { + if ( mHtmlWriter ) { + if ( !cryptProto ) { + QString errorMsg; + switch ( cryptPlugError ) { + case NOT_INITIALIZED: + errorMsg = i18n( "Crypto plug-in \"%1\" is not initialized.", + cryptPlugLibName ); + break; + case CANT_VERIFY_SIGNATURES: + errorMsg = i18n( "Crypto plug-in \"%1\" cannot verify signatures.", + cryptPlugLibName ); + break; + case NO_PLUGIN: + if ( cryptPlugDisplayName.isEmpty() ) + errorMsg = i18n( "No appropriate crypto plug-in was found." ); + else + errorMsg = i18nc( "%1 is either 'OpenPGP' or 'S/MIME'", + "No %1 plug-in was found.", + cryptPlugDisplayName ); + break; + } + messagePart.errorText = i18n( "The message is signed, but the " + "validity of the signature cannot be " + "verified.
" + "Reason: %1", + errorMsg ); + } + + htmlWriter()->queue( writeSigstatHeader( messagePart, + cryptProto, + fromAddress ) ); + } + + ObjectTreeParser otp( mSource, cryptProto, true ); + otp.parseObjectTree( data ); + mRawReplyString += otp.rawReplyString(); + mTextualContent += otp.textualContent(); + if ( !otp.textualContentCharset().isEmpty() ) + mTextualContentCharset = otp.textualContentCharset(); + + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); + } +#ifdef DEBUG_SIGNATURE + kDebug() << "done, returning" << ( bIsOpaqueSigned ? "TRUE" : "FALSE" ); +#endif + kDebug() << "DECRYPTED" << data; + return bIsOpaqueSigned; +} + +void ObjectTreeParser::writeDeferredDecryptionBlock() +{ + const QString iconName = KIconLoader::global()->iconPath( "document-decrypt", + KIconLoader::Small ); + const QString decryptedData = "
" + + i18n("This message is encrypted.") + + "
" + "
"; + PartMetaData messagePart; + messagePart.isDecryptable = true; + messagePart.isEncrypted = true; + messagePart.isSigned = false; + mRawReplyString += decryptedData.toUtf8(); + + if ( mHtmlWriter ) { //TODO: check if this check should be here or at the beginning of the method + htmlWriter()->queue( writeSigstatHeader( messagePart, + cryptoProtocol(), + QString() ) ); + htmlWriter()->queue( decryptedData ); + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); + } +} + + +void ObjectTreeParser::writeDecryptionInProgressBlock() +{ + kDebug(5006) << k_funcinfo << endl; + if ( !mHtmlWriter ) + return; + // PENDING(marc) find an animated icon here: + //const QString iconName = KGlobal::instance()->iconLoader()->iconPath( "decrypted", KIcon::Small ); + const QString decryptedData = i18n("Encrypted data not shown"); + PartMetaData messagePart; + messagePart.isDecryptable = true; + messagePart.isEncrypted = true; + messagePart.isSigned = false; + messagePart.inProgress = true; + htmlWriter()->queue( writeSigstatHeader( messagePart, + cryptoProtocol(), + QString() ) ); + //htmlWriter()->queue( decryptedData ); + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); +} + +bool ObjectTreeParser::okDecryptMIME( KMime::Content& data, + QByteArray& decryptedData, + bool& signatureFound, + std::vector &signatures, + bool showWarning, + bool& passphraseError, + bool& actuallyEncrypted, + bool& decryptionStarted, + QString& aErrorText, + GpgME::Error & auditLogError, + QString& auditLog ) +{ + passphraseError = false; + decryptionStarted = false; + aErrorText.clear(); + auditLogError = GpgME::Error(); + auditLog.clear(); + bool bDecryptionOk = false; + enum { NO_PLUGIN, NOT_INITIALIZED, CANT_DECRYPT } + cryptPlugError = NO_PLUGIN; + + const Kleo::CryptoBackend::Protocol* cryptProto = cryptoProtocol(); + + QString cryptPlugLibName; + if ( cryptProto ) + cryptPlugLibName = cryptProto->name(); + + assert( mSource->decryptMessage() ); + + const QString errorMsg = i18n( "Could not decrypt the data." ); + if ( cryptProto /*FIXME(Andras) port to akonadi + && !kmkernel->contextMenuShown()*/ ) { + QByteArray ciphertext = data.decodedContent(); + #ifdef MARCS_DEBUG + QString cipherStr = QString::fromLatin1( ciphertext ); + bool cipherIsBinary = ( !cipherStr.contains("BEGIN ENCRYPTED MESSAGE", Qt::CaseInsensitive ) ) && + ( !cipherStr.contains("BEGIN PGP ENCRYPTED MESSAGE", Qt::CaseInsensitive ) ) && + ( !cipherStr.contains("BEGIN PGP MESSAGE", Qt::CaseInsensitive ) ); + + dumpToFile( "dat_04_reader.encrypted", ciphertext.data(), ciphertext.size() ); + + QString deb; + deb = "\n\nE N C R Y P T E D D A T A = "; + if ( cipherIsBinary ) + deb += "[binary data]"; + else { + deb += "\""; + deb += cipherStr; + deb += "\""; + } + deb += "\n\n"; + kDebug() << deb; + #endif + + + kDebug() << "going to call CRYPTPLUG" << cryptPlugLibName; + mSource->emitNoDrag(); // in case pineentry pops up, don't let kmheaders start a drag afterwards + + // Check whether the memento contains a result from last time: + const DecryptVerifyBodyPartMemento * m + = dynamic_cast( NodeHelper::instance()->bodyPartMemento( &data, "decryptverify" ) ); + if ( !m ) { + Kleo::DecryptVerifyJob * job = cryptProto->decryptVerifyJob(); + if ( !job ) { + cryptPlugError = CANT_DECRYPT; + cryptProto = 0; + } else { + DecryptVerifyBodyPartMemento * newM + = new DecryptVerifyBodyPartMemento( job, ciphertext ); + if ( allowAsync() ) { + QObject::connect(newM, SIGNAL(update(MessageViewer::Viewer::UpdateMode)), mSource->sourceObject(), SLOT(update(MessageViewer::Viewer::UpdateMode))); + if ( newM->start() ) { + decryptionStarted = true; + mHasPendingAsyncJobs = true; + } else { + m = newM; + } + } else { + newM->exec(); + m = newM; + } + NodeHelper::instance()->setBodyPartMemento( &data, "decryptverify", newM ); + } + } else if ( m->isRunning() ) { + decryptionStarted = true; + mHasPendingAsyncJobs = true; + m = 0; + } + + if ( m ) { + const QByteArray & plainText = m->plainText(); + const GpgME::DecryptionResult & decryptResult = m->decryptResult(); + const GpgME::VerificationResult & verifyResult = m->verifyResult(); + std::stringstream ss; + ss << decryptResult << '\n' << verifyResult; + kDebug() << ss.str().c_str(); + signatureFound = verifyResult.signatures().size() > 0; + signatures = verifyResult.signatures(); + bDecryptionOk = !decryptResult.error(); + passphraseError = decryptResult.error().isCanceled() + || decryptResult.error().code() == GPG_ERR_NO_SECKEY; + actuallyEncrypted = decryptResult.error().code() != GPG_ERR_NO_DATA; + aErrorText = QString::fromLocal8Bit( decryptResult.error().asString() ); + auditLogError = m->auditLogError(); + auditLog = m->auditLogAsHtml(); + + kDebug() << "ObjectTreeParser::decryptMIME: returned from CRYPTPLUG"; + if ( bDecryptionOk ) + decryptedData = plainText; + else if ( mHtmlWriter && showWarning ) { + decryptedData = "
" + + errorMsg.toUtf8() + + "
"; + if ( !passphraseError ) + aErrorText = i18n("Crypto plug-in \"%1\" could not decrypt the data.", cryptPlugLibName ) + + "
" + + i18n("Error: %1", aErrorText ); + } + } +} + +if ( !cryptProto ) { + decryptedData = "
" + + errorMsg.toUtf8() + + "
"; + switch ( cryptPlugError ) { + case NOT_INITIALIZED: + aErrorText = i18n( "Crypto plug-in \"%1\" is not initialized.", + cryptPlugLibName ); + break; + case CANT_DECRYPT: + aErrorText = i18n( "Crypto plug-in \"%1\" cannot decrypt messages.", + cryptPlugLibName ); + break; + case NO_PLUGIN: + aErrorText = i18n( "No appropriate crypto plug-in was found." ); + break; + } +} else if (/*FIXME(Andras) port to akonadi + kmkernel->contextMenuShown()*/ false ) { + // ### Workaround for bug 56693 (kmail freeze with the complete desktop + // ### while pinentry-qt appears) + QByteArray ciphertext( data.decodedContent() ); + QString cipherStr = QString::fromLatin1( ciphertext ); + bool cipherIsBinary = ( !cipherStr.contains("BEGIN ENCRYPTED MESSAGE", Qt::CaseInsensitive ) ) && + ( !cipherStr.contains("BEGIN PGP ENCRYPTED MESSAGE", Qt::CaseInsensitive ) ) && + ( !cipherStr.contains("BEGIN PGP MESSAGE", Qt::CaseInsensitive ) ); + if ( !cipherIsBinary ) { + decryptedData = ciphertext; + } + else { + decryptedData = "
" + + errorMsg.toUtf8() + + "
"; + } +} + +dumpToFile( "dat_05_reader.decrypted", decryptedData.data(), decryptedData.size() ); + +return bDecryptionOk; +} + +//static +bool ObjectTreeParser::containsExternalReferences( const QString & str ) +{ + int httpPos = str.indexOf( "\"http:", Qt::CaseInsensitive ); + int httpsPos = str.indexOf( "\"https:", Qt::CaseInsensitive ); + + while ( httpPos >= 0 || httpsPos >= 0 ) { + // pos = index of next occurrence of "http: or "https: whichever comes first + int pos = ( httpPos < httpsPos ) + ? ( ( httpPos >= 0 ) ? httpPos : httpsPos ) + : ( ( httpsPos >= 0 ) ? httpsPos : httpPos ); + // look backwards for "href" + if ( pos > 5 ) { + int hrefPos = str.lastIndexOf( "href", pos - 5, Qt::CaseInsensitive ); + // if no 'href' is found or the distance between 'href' and '"http[s]:' + // is larger than 7 (7 is the distance in 'href = "http[s]:') then + // we assume that we have found an external reference + if ( ( hrefPos == -1 ) || ( pos - hrefPos > 7 ) ) { + + // HTML messages created by KMail itself for now contain the following: + // + // Make sure not to show an external references warning for this string + int dtdPos = str.indexOf( "http://www.w3.org/TR/REC-html40/strict.dtd", pos + 1 ); + if ( dtdPos != ( pos + 1 ) ) + return true; + } + } + // find next occurrence of "http: or "https: + if ( pos == httpPos ) { + httpPos = str.indexOf( "\"http:", httpPos + 6, Qt::CaseInsensitive ); + } + else { + httpsPos = str.indexOf( "\"https:", httpsPos + 7, Qt::CaseInsensitive ); + } + } + return false; +} + +bool ObjectTreeParser::processTextHtmlSubtype( KMime::Content * curNode, ProcessResult & ) { + const QByteArray partBody( curNode->decodedContent() ); + + mRawReplyString = partBody; + if ( curNode->topLevel()->textContent() == curNode ) { + mTextualContent += curNode->decodedText(); + mTextualContentCharset = curNode->defaultCharset(); + } + + if ( !mHtmlWriter ) + return true; + + QString bodyText; + if ( mSource->htmlMail() ) + bodyText = codecFor( curNode )->toUnicode( partBody ); + else + bodyText = StringUtil::html2source( partBody ); + + if ( curNode->topLevel()->textContent() == curNode || attachmentStrategy()->defaultDisplay( curNode ) == AttachmentStrategy::Inline || + showOnlyOneMimePart() ) + { + if ( mSource->htmlMail() ) { + + HTMLQuoteColorer colorer; + for ( int i = 0; i < 2; i++ ) + colorer.setQuoteColor( i, cssHelper()->quoteColor( i ) ); + bodyText = colorer.process( bodyText ); + NodeHelper::instance()->setNodeDisplayedEmbedded( curNode, true ); + + // Strip , , and , so we don't end up having those tags + // twice, which confuses KHTML (especially with a signed + // multipart/alternative message, the signature bars get rendered at the + // wrong place) + bodyText = bodyText.remove( "", Qt::CaseInsensitive ); + bodyText = bodyText.remove( "", Qt::CaseInsensitive ); + bodyText = bodyText.remove( "", Qt::CaseInsensitive ); + QRegExp bodyRegExp( "" ); //the body tag might have additional attributes, + bodyRegExp.setMinimal( true ); //so make sure to match them as well + bodyRegExp.setCaseSensitivity( Qt::CaseInsensitive ); + bodyText = bodyText.remove( bodyRegExp ); + + // Strip and from end. + // We must do this, or else the message will not be displayed correctly + // because we have two or tags in the generated HTML. + // It is IMHO enough to search only for and put \0 there. + int i = bodyText.lastIndexOf( "", -1, Qt::CaseInsensitive ); + if ( 0 <= i ) + bodyText.truncate(i); + else { // just in case - search for + i = bodyText.lastIndexOf( "", -1, Qt::CaseInsensitive ); + if ( 0 <= i ) + bodyText.truncate(i); + } + + // Show the "external references" warning (with possibility to load + // external references only if loading external references is disabled + // and the HTML code contains obvious external references). For + // messages where the external references are obfuscated the user won't + // have an easy way to load them but that shouldn't be a problem + // because only spam contains obfuscated external references. + if ( !mSource->htmlLoadExternal() && + containsExternalReferences( bodyText ) ) { + htmlWriter()->queue( "
\n" ); + htmlWriter()->queue( i18n("Note: This HTML message may contain external " + "references to images etc. For security/privacy reasons " + "external references are not loaded. If you trust the " + "sender of this message then you can load the external " + "references for this message " + "by clicking here.") ); + htmlWriter()->queue( "


" ); + } + } else { + htmlWriter()->queue( "
\n" ); + htmlWriter()->queue( i18n("Note: This is an HTML message. For " + "security reasons, only the raw HTML code " + "is shown. If you trust the sender of this " + "message then you can activate formatted " + "HTML display for this message " + "by clicking here.") ); + htmlWriter()->queue( "


" ); + } + // Make sure the body is relative, so that nothing is painted over above "Note: ..." + // if a malicious message uses absolute positioning. #137643 + htmlWriter()->queue( "
\n" ); + htmlWriter()->queue( bodyText ); + htmlWriter()->queue( "
\n" ); + mSource->setHtmlMode( true ); + return true; + } + return false; +} + +bool ObjectTreeParser::isMailmanMessage( KMime::Content * curNode ) +{ + if ( !curNode || curNode->head().isEmpty() ) + return false; + if ( curNode->hasHeader("X-Mailman-Version") ) + return true; + if ( curNode->hasHeader("X-Mailer") ) { + KMime::Headers::Base *header = curNode->headerByType("X-Mailer"); + if ( header->asUnicodeString().contains("MAILMAN", Qt::CaseInsensitive ) ) + return true; + } + return false; +} + +bool ObjectTreeParser::processMailmanMessage( KMime::Content* curNode ) { + const QString str = QString::fromLatin1( curNode->decodedContent() ); + + //### + const QLatin1String delim1( "--__--__--\n\nMessage:" ); + const QLatin1String delim2( "--__--__--\r\n\r\nMessage:" ); + const QLatin1String delimZ2( "--__--__--\n\n_____________" ); + const QLatin1String delimZ1( "--__--__--\r\n\r\n_____________" ); + QString partStr, digestHeaderStr; + int thisDelim = str.indexOf( delim1, Qt::CaseInsensitive ); + if ( thisDelim == -1 ) { + thisDelim = str.indexOf( delim2, Qt::CaseInsensitive ); + } + if ( thisDelim == -1 ) { + return false; + } + + int nextDelim = str.indexOf( delim1, thisDelim+1, Qt::CaseInsensitive ); + if ( -1 == nextDelim ) { + nextDelim = str.indexOf( delim2, thisDelim+1, Qt::CaseInsensitive ); + } + if ( -1 == nextDelim ) { + nextDelim = str.indexOf( delimZ1, thisDelim+1, Qt::CaseInsensitive ); + } + if ( -1 == nextDelim ) { + nextDelim = str.indexOf( delimZ2, thisDelim+1, Qt::CaseInsensitive ); + } + if ( nextDelim < 0) { + return false; + } + + //if ( curNode->mRoot ) + // curNode = curNode->mRoot; + + // at least one message found: build a mime tree + digestHeaderStr = "Content-Type: text/plain\nContent-Description: digest header\n\n"; + digestHeaderStr += str.mid( 0, thisDelim ); + insertAndParseNewChildNode( *curNode, + digestHeaderStr.toLatin1(), + "Digest Header", true ); + //mReader->queueHtml("


"); + // temporarily change curent node's Content-Type + // to get our embedded RfC822 messages properly inserted + curNode->contentType()->setMimeType( "multipart/digest" ); + while( -1 < nextDelim ){ + int thisEoL = str.indexOf("\nMessage:", thisDelim, Qt::CaseInsensitive ); + if ( -1 < thisEoL ) + thisDelim = thisEoL+1; + else{ + thisEoL = str.indexOf("\n_____________", thisDelim, Qt::CaseInsensitive ); + if ( -1 < thisEoL ) + thisDelim = thisEoL+1; + } + thisEoL = str.indexOf( '\n', thisDelim ); + if ( -1 < thisEoL ) + thisDelim = thisEoL+1; + else + thisDelim = thisDelim+1; + //while( thisDelim < cstr.size() && '\n' == cstr[thisDelim] ) + // ++thisDelim; + + partStr = "Content-Type: message/rfc822\nContent-Description: embedded message\n\n"; + partStr += str.mid( thisDelim, nextDelim-thisDelim ); + QString subject = QString::fromLatin1("embedded message"); + QString subSearch = QString::fromLatin1("\nSubject:"); + int subPos = partStr.indexOf(subSearch, 0, Qt::CaseInsensitive ); + if ( -1 < subPos ){ + subject = partStr.mid(subPos+subSearch.length()); + thisEoL = subject.indexOf('\n'); + if ( -1 < thisEoL ) + subject.truncate( thisEoL ); + } + kDebug() << " embedded message found: \"" << subject; + insertAndParseNewChildNode( *curNode, + partStr.toLatin1(), + subject.toLatin1(), true ); + //mReader->queueHtml("


"); + thisDelim = nextDelim+1; + nextDelim = str.indexOf(delim1, thisDelim, Qt::CaseInsensitive ); + if ( -1 == nextDelim ) + nextDelim = str.indexOf(delim2, thisDelim, Qt::CaseInsensitive); + if ( -1 == nextDelim ) + nextDelim = str.indexOf(delimZ1, thisDelim, Qt::CaseInsensitive); + if ( -1 == nextDelim ) + nextDelim = str.indexOf(delimZ2, thisDelim, Qt::CaseInsensitive); + } + // reset curent node's Content-Type + curNode->contentType()->setMimeType( "text/plain" ); + int thisEoL = str.indexOf( "_____________", thisDelim ); + if ( -1 < thisEoL ){ + thisDelim = thisEoL; + thisEoL = str.indexOf( '\n', thisDelim ); + if ( -1 < thisEoL ) + thisDelim = thisEoL+1; + } + else + thisDelim = thisDelim+1; + partStr = "Content-Type: text/plain\nContent-Description: digest footer\n\n"; + partStr += str.mid( thisDelim ); + insertAndParseNewChildNode( *curNode, + partStr.toLatin1(), + "Digest Footer", true ); + return true; +} + +bool ObjectTreeParser::processTextPlainSubtype( KMime::Content *curNode, ProcessResult & result ) +{ + bool isFirstTextPart = (curNode->topLevel()->textContent() == curNode); + + if ( !mHtmlWriter ) { + mRawReplyString = curNode->decodedContent(); + if ( isFirstTextPart ) { + mTextualContent += curNode->decodedText(); + mTextualContentCharset = curNode->defaultCharset(); + } + return true; + } + + if ( !isFirstTextPart && attachmentStrategy()->defaultDisplay( curNode ) != AttachmentStrategy::Inline && + !showOnlyOneMimePart() ) + return false; + + mRawReplyString = curNode->decodedContent(); + if ( isFirstTextPart ) { + mTextualContent += curNode->decodedText(); + mTextualContentCharset = curNode->defaultCharset(); + } + + QString label = NodeHelper::fileName( curNode ); + + const bool bDrawFrame = !isFirstTextPart + && !showOnlyOneMimePart() + && !label.isEmpty(); + if ( bDrawFrame ) { + label = StringUtil::quoteHtmlChars( label, true ); + + const QString comment = + StringUtil::quoteHtmlChars( curNode->contentDescription()->asUnicodeString(), true ); + + const QString fileName; + NodeHelper::instance()->writeNodeToTempFile( curNode ); + const QString dir = QApplication::isRightToLeft() ? "rtl" : "ltr" ; + + QString htmlStr = "" + "
"; + if ( !fileName.isEmpty() ) + htmlStr += "" + + label + ""; + else + htmlStr += label; + if ( !comment.isEmpty() ) + htmlStr += "
" + comment; + htmlStr += "
"; + + htmlWriter()->queue( htmlStr ); + } + // process old style not-multipart Mailman messages to + // enable verification of the embedded messages' signatures + if ( !isMailmanMessage( curNode ) || + !processMailmanMessage( curNode ) ) { + writeBodyString( mRawReplyString, static_cast(curNode->topLevel())->from()->asUnicodeString(), + codecFor( curNode ), result, !bDrawFrame ); + NodeHelper::instance()->setNodeDisplayedEmbedded( curNode, true ); + } + if ( bDrawFrame ) + htmlWriter()->queue( "
" ); + + return true; +} + +void ObjectTreeParser::stdChildHandling( KMime::Content * child ) { + if ( !child ) + return; + + ObjectTreeParser otp( *this ); + otp.setShowOnlyOneMimePart( false ); + otp.parseObjectTree( child ); + mRawReplyString += otp.rawReplyString(); + mTextualContent += otp.textualContent(); + if ( !otp.textualContentCharset().isEmpty() ) + mTextualContentCharset = otp.textualContentCharset(); +} + +bool ObjectTreeParser::processMultiPartMixedSubtype( KMime::Content * node, ProcessResult & ) +{ + KMime::Content * child = NodeHelper::firstChild( node ); + if ( !child ) + return false; + + // normal treatment of the parts in the mp/mixed container + stdChildHandling( child ); + return true; +} + +bool ObjectTreeParser::processMultiPartAlternativeSubtype( KMime::Content * node, ProcessResult & ) +{ + KMime::Content * child = NodeHelper::firstChild( node ); + if ( !child ) + return false; + + KMime::Content* dataHtml = findType( child, "text/html", false, true ); + if ( !dataHtml ) { + // If we didn't find the HTML part as the first child of the multipart/alternative, it might + // be that this is a HTML message with images, and text/plain and multipart/related are the + // immediate children of this multipart/alternative node. + // In this case, the HTML node is a child of multipart/related. + dataHtml = findType( child, "multipart/related", false, true ); + } + KMime::Content* dataPlain = findType( child, "text/plain", false, true ); + + if ( ( mSource->htmlMail() && dataHtml) || + (dataHtml && dataPlain && dataPlain->body().isEmpty()) ) { + if ( dataPlain ) + NodeHelper::instance()->setNodeProcessed( dataPlain, false); + stdChildHandling( dataHtml ); + return true; + } + + if ( !mHtmlWriter || (!mSource->htmlMail() && dataPlain) ) { + NodeHelper::instance()->setNodeProcessed( dataHtml, false ); + stdChildHandling( dataPlain ); + return true; + } + + stdChildHandling( child ); + return true; +} + +bool ObjectTreeParser::processMultiPartDigestSubtype( KMime::Content * node, ProcessResult & result ) { + return processMultiPartMixedSubtype( node, result ); +} + +bool ObjectTreeParser::processMultiPartParallelSubtype( KMime::Content * node, ProcessResult & result ) { + return processMultiPartMixedSubtype( node, result ); +} + +bool ObjectTreeParser::processMultiPartSignedSubtype( KMime::Content * node, ProcessResult & ) +{ + KMime::Content * child = NodeHelper::firstChild( node ); + if ( node->contents().size() != 2 ) { + kDebug() << "mulitpart/signed must have exactly two child parts!" << endl + << "processing as multipart/mixed"; + if ( child ) + stdChildHandling( child ); + return child; + } + + KMime::Content * signedData = child; + assert( signedData ); + + KMime::Content * signature = node->contents().at(1); + assert( signature ); + + NodeHelper::instance()->setNodeProcessed( signature, true); + + if ( !includeSignatures() ) { + stdChildHandling( signedData ); + return true; + } + + QString protocolContentType = node->contentType()->parameter( "protocol" ).toLower(); + const QString signatureContentType = signature->contentType()->mimeType().toLower(); + if ( protocolContentType.isEmpty() ) { + kWarning() << "Message doesn't set the protocol for the multipart/signed content-type, " + "using content-type of the signature:" << signatureContentType; + protocolContentType = signatureContentType; + } + + const Kleo::CryptoBackend::Protocol *protocol = 0; + if ( protocolContentType == "application/pkcs7-signature" || + protocolContentType == "application/x-pkcs7-signature" ) + protocol = Kleo::CryptoBackendFactory::instance()->smime(); + else if ( protocolContentType == "application/pgp-signature" || + protocolContentType == "application/x-pgp-signature" ) + protocol = Kleo::CryptoBackendFactory::instance()->openpgp(); + + if ( !protocol ) { + NodeHelper::instance()->setNodeProcessed( signature, true ); + stdChildHandling( signedData ); + return true; + } + + CryptoProtocolSaver saver( this, protocol ); + NodeHelper::instance()->setSignatureState( node, KMMsgFullySigned); + + writeOpaqueOrMultipartSignedData( signedData, *signature, + static_cast(node->topLevel())->from()->asUnicodeString() ); + return true; +} + +bool ObjectTreeParser::processMultiPartEncryptedSubtype( KMime::Content * node, ProcessResult & result ) +{ + KMime::Content * child = NodeHelper::firstChild( node ); + if ( !child ) + return false; + + if ( keepEncryptions() ) { + NodeHelper::instance()->setEncryptionState( node, KMMsgFullyEncrypted ); + const QByteArray cstr = node->decodedContent(); + if ( mHtmlWriter ) + writeBodyString( cstr, static_cast(node->topLevel())->from()->asUnicodeString(), + codecFor( node ), result, false ); + mRawReplyString += cstr; + return true; + } + + const Kleo::CryptoBackend::Protocol * useThisCryptProto = 0; + + /* + ATTENTION: This code is to be replaced by the new 'auto-detect' feature. -------------------------------------- + */ + KMime::Content* data = findType( child, "application/octet-stream", false, true ); + if ( data ) { + useThisCryptProto = Kleo::CryptoBackendFactory::instance()->openpgp(); + } + if ( !data ) { + data = findType( child, "application/pkcs7-mime", false, true ); + if ( data ) { + useThisCryptProto = Kleo::CryptoBackendFactory::instance()->smime(); + } + } + /* + --------------------------------------------------------------------------------------------------------------- + */ + + if ( !data ) { + stdChildHandling( child ); + return true; + } + + CryptoProtocolSaver cpws( this, useThisCryptProto ); + + KMime::Content * dataChild = NodeHelper::firstChild( data ); + if ( dataChild ) { + stdChildHandling( dataChild ); + return true; + } + + NodeHelper::instance()->setEncryptionState( node, KMMsgFullyEncrypted ); + + if ( !mSource->decryptMessage() ) { + writeDeferredDecryptionBlock(); + NodeHelper::instance()->setNodeProcessed( data, false );// Set the data node to done to prevent it from being processed + return true; + } + + PartMetaData messagePart; + QByteArray decryptedData; + bool signatureFound; + std::vector signatures; + bool passphraseError; + bool actuallyEncrypted = true; + bool decryptionStarted; + + bool bOkDecrypt = okDecryptMIME( *data, + decryptedData, + signatureFound, + signatures, + true, + passphraseError, + actuallyEncrypted, + decryptionStarted, + messagePart.errorText, + messagePart.auditLogError, + messagePart.auditLog ); + + if ( decryptionStarted ) { + writeDecryptionInProgressBlock(); + return true; + } + + // paint the frame + if ( mHtmlWriter ) { + messagePart.isDecryptable = bOkDecrypt; + messagePart.isEncrypted = true; + messagePart.isSigned = false; + htmlWriter()->queue( writeSigstatHeader( messagePart, + cryptoProtocol(), + static_cast(node->topLevel())->from()->asUnicodeString() ) ); + } + + if ( bOkDecrypt ) { + // Note: Multipart/Encrypted might also be signed + // without encapsulating a nicely formatted + // ~~~~~~~ Multipart/Signed part. + // (see RFC 3156 --> 6.2) + // In this case we paint a _2nd_ frame inside the + // encryption frame, but we do _not_ show a respective + // encapsulated MIME part in the Mime Tree Viewer + // since we do want to show the _true_ structure of the + // message there - not the structure that the sender's + // MUA 'should' have sent. :-D (khz, 12.09.2002) + // + if ( signatureFound ) { + writeOpaqueOrMultipartSignedData( 0, + *node, + static_cast(node->topLevel())->from()->asUnicodeString(), + false, + &decryptedData, + signatures, + false ); + NodeHelper::instance()->setSignatureState( node, KMMsgFullySigned); + } else { + decryptedData = KMime::CRLFtoLF( decryptedData ); //KMime works with LF only inside insertAndParseNewChildNode + insertAndParseNewChildNode( *node, + decryptedData.constData(), + "encrypted data" ); + } + } else { + mRawReplyString += decryptedData; + if ( mHtmlWriter ) { + // print the error message that was returned in decryptedData + // (utf8-encoded) + htmlWriter()->queue( QString::fromUtf8( decryptedData.data() ) ); + } + } + + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); + NodeHelper::instance()->setNodeProcessed( data, false ); // Set the data node to done to prevent it from being processed + return true; +} + + +bool ObjectTreeParser::processMessageRfc822Subtype( KMime::Content * node, ProcessResult & ) +{ + if ( mHtmlWriter + && !attachmentStrategy()->inlineNestedMessages() + && !showOnlyOneMimePart() ) + return false; + + KMime::Content * child = NodeHelper::firstChild( node ); + if ( child ) { + ObjectTreeParser otp( mSource, cryptoProtocol() ); + otp.parseObjectTree( child ); + mRawReplyString += otp.rawReplyString(); + mTextualContent += otp.textualContent(); + if ( !otp.textualContentCharset().isEmpty() ) + mTextualContentCharset = otp.textualContentCharset(); + return true; + } + // paint the frame + PartMetaData messagePart; + if ( mHtmlWriter ) { + messagePart.isEncrypted = false; + messagePart.isSigned = false; + messagePart.isEncapsulatedRfc822Message = true; + QString filename = NodeHelper::instance()->writeNodeToTempFile( node ); + htmlWriter()->queue( writeSigstatHeader( messagePart, + cryptoProtocol(), + static_cast(node->topLevel())->from()->asUnicodeString(), + node ) ); + } + QByteArray rfc822messageStr( node->decodedContent() ); + // display the headers of the encapsulated message + KMime::Message* rfc822message = new KMime::Message(); + rfc822message->setContent( rfc822messageStr ); + rfc822message->parse(); + static_cast(node->topLevel())->from()->from7BitString( rfc822message->from()->as7BitString() ); + if ( mHtmlWriter ) + htmlWriter()->queue( mSource->createMessageHeader( rfc822message ) ); + delete rfc822message; + //mReader->parseMsgHeader( &rfc822message ); + // display the body of the encapsulated message + insertAndParseNewChildNode( *node, + rfc822messageStr.constData(), + "encapsulated message", false /*append*/, + false /*add to textual content*/ ); + NodeHelper::instance()->setNodeDisplayedEmbedded( node, true ); + + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); + return true; +} + + +bool ObjectTreeParser::processApplicationOctetStreamSubtype( KMime::Content * node, ProcessResult & result ) +{ + KMime::Content * child = NodeHelper::firstChild( node ); + if ( child ) { + ObjectTreeParser otp( mSource, cryptoProtocol() ); + otp.parseObjectTree( child ); + mRawReplyString += otp.rawReplyString(); + mTextualContent += otp.textualContent(); + if ( !otp.textualContentCharset().isEmpty() ) + mTextualContentCharset = otp.textualContentCharset(); + return true; + } + + const Kleo::CryptoBackend::Protocol* oldUseThisCryptPlug = cryptoProtocol(); + if ( node->parent() + && node->parent()->contentType()->mimeType() == "multipart/encrypted" ) { + NodeHelper::instance()->setEncryptionState( node, KMMsgFullyEncrypted ); + if ( keepEncryptions() ) { + const QByteArray cstr = node->decodedContent(); + if ( mHtmlWriter ) + writeBodyString( cstr, static_cast(node->topLevel())->from()->asUnicodeString(), + codecFor( node ), result, false ); + mRawReplyString += cstr; + } else if ( !mSource->decryptMessage() ) { + writeDeferredDecryptionBlock(); + } else { + /* + ATTENTION: This code is to be replaced by the planned 'auto-detect' feature. + */ + PartMetaData messagePart; + setCryptoProtocol( Kleo::CryptoBackendFactory::instance()->openpgp() ); + QByteArray decryptedData; + bool signatureFound; + std::vector signatures; + bool passphraseError; + bool actuallyEncrypted = true; + bool decryptionStarted; + + bool bOkDecrypt = okDecryptMIME( *node, + decryptedData, + signatureFound, + signatures, + true, + passphraseError, + actuallyEncrypted, + decryptionStarted, + messagePart.errorText, + messagePart.auditLogError, + messagePart.auditLog ); + + if ( decryptionStarted ) { + writeDecryptionInProgressBlock(); + return true; + } + + // paint the frame + if ( mHtmlWriter ) { + messagePart.isDecryptable = bOkDecrypt; + messagePart.isEncrypted = true; + messagePart.isSigned = false; + htmlWriter()->queue( writeSigstatHeader( messagePart, + cryptoProtocol(), + static_cast(node->topLevel())->from()->asUnicodeString() ) ); + } + + if ( bOkDecrypt ) { + // fixing the missing attachments bug #1090-b + insertAndParseNewChildNode( *node, + decryptedData.constData(), + "encrypted data" ); + } else { + mRawReplyString += decryptedData; + if ( mHtmlWriter ) { + // print the error message that was returned in decryptedData + // (utf8-encoded) + htmlWriter()->queue( QString::fromUtf8( decryptedData.data() ) ); + } + } + + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); + } + return true; + } + setCryptoProtocol( oldUseThisCryptPlug ); + return false; +} + +bool ObjectTreeParser::processApplicationPkcs7MimeSubtype( KMime::Content * node, ProcessResult & result ) +{ + KMime::Content * child = NodeHelper::firstChild( node ); + if ( child ) { + ObjectTreeParser otp( mSource, cryptoProtocol() ); + otp.parseObjectTree( child ); + mRawReplyString += otp.rawReplyString(); + mTextualContent += otp.textualContent(); + if ( !otp.textualContentCharset().isEmpty() ) + mTextualContentCharset = otp.textualContentCharset(); + return true; + } + + if ( node->head().isEmpty() ) + return false; + + const Kleo::CryptoBackend::Protocol * smimeCrypto = Kleo::CryptoBackendFactory::instance()->smime(); + + const QString smimeType = node->contentType()->parameter("smime-type").toLower(); + + if ( smimeType == "certs-only" ) { + result.setNeverDisplayInline( true ); + if ( !smimeCrypto || !mHtmlWriter ) + return false; + + const KConfigGroup reader( Global::instance()->config(), "Reader" ); + if ( !reader.readEntry( "AutoImportKeys", false ) ) + return false; + + const QByteArray certData = node->decodedContent(); + + Kleo::ImportJob *import = smimeCrypto->importJob(); + KleoJobExecutor executor; + const GpgME::ImportResult res = executor.exec( import, certData ); + if ( res.error() ) { + htmlWriter()->queue( i18n( "Sorry, certificate could not be imported.
" + "Reason: %1", QString::fromLocal8Bit( res.error().asString() ) ) ); + return true; + } + + const int nImp = res.numImported(); + const int nUnc = res.numUnchanged(); + const int nSKImp = res.numSecretKeysImported(); + const int nSKUnc = res.numSecretKeysUnchanged(); + if ( !nImp && !nSKImp && !nUnc && !nSKUnc ) { + htmlWriter()->queue( i18n( "Sorry, no certificates were found in this message." ) ); + return true; + } + QString comment = "" + i18n( "Certificate import status:" ) + "
 
"; + if ( nImp ) + comment += i18np( "1 new certificate was imported.", + "%1 new certificates were imported.", nImp ) + "
"; + if ( nUnc ) + comment += i18np( "1 certificate was unchanged.", + "%1 certificates were unchanged.", nUnc ) + "
"; + if ( nSKImp ) + comment += i18np( "1 new secret key was imported.", + "%1 new secret keys were imported.", nSKImp ) + "
"; + if ( nSKUnc ) + comment += i18np( "1 secret key was unchanged.", + "%1 secret keys were unchanged.", nSKUnc ) + "
"; + comment += " 
"; + htmlWriter()->queue( comment ); + if ( !nImp && !nSKImp ) { + htmlWriter()->queue( "
" ); + return true; + } + const std::vector imports = res.imports(); + if ( imports.empty() ) { + htmlWriter()->queue( i18n( "Sorry, no details on certificate import available." ) + "
" ); + return true; + } + htmlWriter()->queue( "" + i18n( "Certificate import details:" ) + "
" ); + for ( std::vector::const_iterator it = imports.begin() ; it != imports.end() ; ++it ) { + if ( (*it).error() ) { + htmlWriter()->queue( i18nc( "Certificate import failed.", "Failed: %1 (%2)", (*it).fingerprint(), + QString::fromLocal8Bit( (*it).error().asString() ) ) ); + } else if ( (*it).status() & ~GpgME::Import::ContainedSecretKey ) { + if ( (*it).status() & GpgME::Import::ContainedSecretKey ) { + htmlWriter()->queue( i18n( "New or changed: %1 (secret key available)", (*it).fingerprint() ) ); + } else { + htmlWriter()->queue( i18n( "New or changed: %1", (*it).fingerprint() ) ); + } + } + htmlWriter()->queue( "
" ); + } + + htmlWriter()->queue( "
" ); + return true; + } + + if ( !smimeCrypto ) + return false; + CryptoProtocolSaver cpws( this, smimeCrypto ); + + bool isSigned = smimeType == "signed-data"; + bool isEncrypted = smimeType == "enveloped-data"; + + // Analyze "signTestNode" node to find/verify a signature. + // If zero this verification was successfully done after + // decrypting via recursion by insertAndParseNewChildNode(). + KMime::Content* signTestNode = isEncrypted ? 0 : node; + + + // We try decrypting the content + // if we either *know* that it is an encrypted message part + // or there is neither signed nor encrypted parameter. + if ( !isSigned ) { + if ( isEncrypted ) + kDebug() << "pkcs7 mime == S/MIME TYPE: enveloped (encrypted) data"; + else + kDebug() << "pkcs7 mime - type unknown - enveloped (encrypted) data ?"; + QByteArray decryptedData; + PartMetaData messagePart; + messagePart.isEncrypted = true; + messagePart.isSigned = false; + bool signatureFound; + std::vector signatures; + bool passphraseError; + bool actuallyEncrypted = true; + bool decryptionStarted; + + if ( !mSource->decryptMessage() ) { + writeDeferredDecryptionBlock(); + isEncrypted = true; + } else if ( okDecryptMIME( *node, + decryptedData, + signatureFound, + signatures, + false, + passphraseError, + actuallyEncrypted, + decryptionStarted, + messagePart.errorText, + messagePart.auditLogError, + messagePart.auditLog ) ) { + kDebug() << "pkcs7 mime - encryption found - enveloped (encrypted) data !"; + isEncrypted = true; + NodeHelper::instance()->setEncryptionState( node, KMMsgFullyEncrypted ); + signTestNode = 0; + if ( decryptionStarted ) { + writeDecryptionInProgressBlock(); + } else { + // paint the frame + messagePart.isDecryptable = true; + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatHeader( messagePart, + cryptoProtocol(), + static_cast(node->topLevel())->from()->asUnicodeString() ) ); + insertAndParseNewChildNode( *node, + &*decryptedData, + "encrypted data" ); + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); + } + } else { + // decryption failed, which could be because the part was encrypted but + // decryption failed, or because we didn't know if it was encrypted, tried, + // and failed. If the message was not actually encrypted, we continue + // assuming it's signed + if ( passphraseError || ( smimeType.isEmpty() && actuallyEncrypted ) ) { + isEncrypted = true; + signTestNode = 0; + } + + if ( isEncrypted ) { + kDebug() << "pkcs7 mime - ERROR: COULD NOT DECRYPT enveloped data !"; + // paint the frame + messagePart.isDecryptable = false; + if ( mHtmlWriter ) { + htmlWriter()->queue( writeSigstatHeader( messagePart, + cryptoProtocol(), + static_cast(node->topLevel())->from()->asUnicodeString() ) ); + assert( mSource->decryptMessage() ); // handled above + writePartIcon( node ); + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); + } + } else { + kDebug() << "pkcs7 mime - NO encryption found"; + } + } + if ( isEncrypted ) + NodeHelper::instance()->setEncryptionState( node, KMMsgFullyEncrypted ); + } + + // We now try signature verification if necessarry. + if ( signTestNode ) { + if ( isSigned ) + kDebug() << "pkcs7 mime == S/MIME TYPE: opaque signed data"; + else + kDebug() << "pkcs7 mime - type unknown - opaque signed data ?"; + + bool sigFound = writeOpaqueOrMultipartSignedData( 0, + *signTestNode, + static_cast(node->topLevel())->from()->asUnicodeString(), + true, + 0, + std::vector(), + isEncrypted ); + if ( sigFound ) { + if ( !isSigned ) { + kDebug() << "pkcs7 mime - signature found - opaque signed data !"; + isSigned = true; + } + + NodeHelper::instance()->setSignatureState( signTestNode, KMMsgFullySigned ); + if ( signTestNode != node ) + NodeHelper::instance()->setSignatureState( node, KMMsgFullySigned ); + } else { + kDebug() << "pkcs7 mime - NO signature found :-("; + } + } + + return isSigned || isEncrypted; +} + +bool ObjectTreeParser::decryptChiasmus( const QByteArray& data, QByteArray& bodyDecoded, QString& errorText ) +{ + const Kleo::CryptoBackend::Protocol * chiasmus = + Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ); + Q_ASSERT( chiasmus ); + if ( !chiasmus ) + return false; + + const std::auto_ptr listjob( chiasmus->specialJob( "x-obtain-keys", QMap() ) ); + if ( !listjob.get() ) { + errorText = i18n( "Chiasmus backend does not offer the " + "\"x-obtain-keys\" function. Please report this bug." ); + return false; + } + + if ( listjob->exec() ) { + errorText = i18n( "Chiasmus Backend Error" ); + return false; + } + + const QVariant result = listjob->property( "result" ); + if ( result.type() != QVariant::StringList ) { + errorText = i18n( "Unexpected return value from Chiasmus backend: " + "The \"x-obtain-keys\" function did not return a " + "string list. Please report this bug." ); + return false; + } + + const QStringList keys = result.toStringList(); + if ( keys.empty() ) { + errorText = i18n( "No keys have been found. Please check that a " + "valid key path has been set in the Chiasmus " + "configuration." ); + return false; + } + + mSource->emitNoDrag(); + /*FIXME(Andras) port to akonadi + ChiasmusKeySelector selectorDlg( mReader, i18n( "Chiasmus Decryption Key Selection" ), + keys, GlobalSettings::chiasmusDecryptionKey(), + GlobalSettings::chiasmusDecryptionOptions() ); + if ( selectorDlg.exec() != KDialog::Accepted ) + return false; + GlobalSettings::setChiasmusDecryptionOptions( selectorDlg.options() ); + GlobalSettings::setChiasmusDecryptionKey( selectorDlg.key() ); + assert( !GlobalSettings::chiasmusDecryptionKey().isEmpty() ); + */ + + Kleo::SpecialJob * job = chiasmus->specialJob( "x-decrypt", QMap() ); + if ( !job ) { + errorText = i18n( "Chiasmus backend does not offer the " + "\"x-decrypt\" function. Please report this bug." ); + return false; + } + + if ( !job->setProperty( "key", GlobalSettings::chiasmusDecryptionKey() ) || + !job->setProperty( "options", GlobalSettings::chiasmusDecryptionOptions() ) || + !job->setProperty( "input", data ) ) { + errorText = i18n( "The \"x-decrypt\" function does not accept " + "the expected parameters. Please report this bug." ); + return false; + } + + if ( job->exec() ) { + errorText = i18n( "Chiasmus Decryption Error" ); + return false; + } + + const QVariant resultData = job->property( "result" ); + if ( resultData.type() != QVariant::ByteArray ) { + errorText = i18n( "Unexpected return value from Chiasmus backend: " + "The \"x-decrypt\" function did not return a " + "byte array. Please report this bug." ); + return false; + } + bodyDecoded = resultData.toByteArray(); + return true; + } + + bool ObjectTreeParser::processApplicationChiasmusTextSubtype( KMime::Content * curNode, ProcessResult & result ) + { + if ( !mHtmlWriter ) { + mRawReplyString = curNode->decodedContent(); + mTextualContent += curNode->decodedText(); + mTextualContentCharset = curNode->defaultCharset(); + return true; + } + + QByteArray decryptedBody; + QString errorText; + const QByteArray data = curNode->decodedContent(); + bool bOkDecrypt = decryptChiasmus( data, decryptedBody, errorText ); + PartMetaData messagePart; + messagePart.isDecryptable = bOkDecrypt; + messagePart.isEncrypted = true; + messagePart.isSigned = false; + messagePart.errorText = errorText; + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatHeader( messagePart, + 0, //cryptPlugWrapper(), + static_cast(curNode->topLevel())->from()->asUnicodeString() ) ); + const QByteArray body = bOkDecrypt ? decryptedBody : data; + const QString chiasmusCharset = curNode->contentType()->parameter("chiasmus-charset"); + const QTextCodec* aCodec = chiasmusCharset.isEmpty() ? codecFor( curNode ) + : NodeHelper::codecForName( chiasmusCharset.toAscii() ); + htmlWriter()->queue( quotedHTML( aCodec->toUnicode( body ), false /*decorate*/ ) ); + result.setInlineEncryptionState( KMMsgFullyEncrypted ); + if ( mHtmlWriter ) + htmlWriter()->queue( writeSigstatFooter( messagePart ) ); + return true; +} + +bool ObjectTreeParser::processApplicationMsTnefSubtype( KMime::Content *node, ProcessResult &result ) +{ + Q_UNUSED( result ); + if ( !mHtmlWriter ) + return false; + + const QString fileName = NodeHelper::instance()->writeNodeToTempFile( node ); + KTnef::KTNEFParser parser; + if ( !parser.openFile( fileName ) || !parser.message()) { + kDebug() << "Could not parse" << fileName; + return false; + } + + QList tnefatts = parser.message()->attachmentList(); + if ( tnefatts.isEmpty() ) { + kDebug() << "No attachments found in" << fileName; + return false; + } + + if ( !showOnlyOneMimePart() ) { + QString label = NodeHelper::fileName( node ); + label = StringUtil::quoteHtmlChars( label, true ); + const QString comment = StringUtil::quoteHtmlChars( node->contentDescription()->asUnicodeString(), true ); + const QString dir = QApplication::isRightToLeft() ? "rtl" : "ltr" ; + + QString htmlStr = "" + "
"; + if ( !fileName.isEmpty() ) + htmlStr += "" + + label + ""; + else + htmlStr += label; + if ( !comment.isEmpty() ) + htmlStr += "
" + comment; + htmlStr += "
"; + htmlWriter()->queue( htmlStr ); + } + + for ( int i = 0; i < tnefatts.count(); ++i ) { + KTnef::KTNEFAttach *att = tnefatts.at( i ); + QString label = att->displayName(); + if( label.isEmpty() ) + label = att->name(); + label = StringUtil::quoteHtmlChars( label, true ); + + QString dir = NodeHelper::instance()->createTempDir( "ktnef-" + QString::number( i ) ); + parser.extractFileTo( att->name(), dir ); + NodeHelper::instance()->addTempFile( dir + QDir::separator() + att->name() ); + QString href = "file:" + KUrl::toPercentEncoding( dir + QDir::separator() + att->name() ); + + KMimeType::Ptr mimeType = KMimeType::mimeType( att->mimeTag(), KMimeType::ResolveAliases ); + QString iconName = KIconLoader::global()->iconPath( mimeType->iconName(), KIconLoader::Desktop ); + + htmlWriter()->queue( "
" ); + } + + if ( !showOnlyOneMimePart() ) + htmlWriter()->queue( "
" ); + + return true; +} + +void ObjectTreeParser::writeBodyString( const QByteArray & bodyString, + const QString & fromAddress, + const QTextCodec * codec, + ProcessResult & result, + bool decorate ) +{ + if ( !mHtmlWriter ) + return; + assert( codec ); + KMMsgSignatureState inlineSignatureState = result.inlineSignatureState(); + KMMsgEncryptionState inlineEncryptionState = result.inlineEncryptionState(); + writeBodyStr( bodyString, codec, fromAddress, + inlineSignatureState, inlineEncryptionState, decorate ); + result.setInlineSignatureState( inlineSignatureState ); + result.setInlineEncryptionState( inlineEncryptionState ); +} + +void ObjectTreeParser::writePartIcon( KMime::Content * msgPart, bool inlineImage ) +{ + if ( !mHtmlWriter || !msgPart ) + return; + + QString label = NodeHelper::fileName( msgPart ); + if ( label.isEmpty() ) + label = i18nc( "display name for an unnamed attachment", "Unnamed" ); + label = StringUtil::quoteHtmlChars( label, true ); + + QString comment = msgPart->contentDescription()->asUnicodeString(); + comment = StringUtil::quoteHtmlChars( comment, true ); + if ( label == comment ) + comment.clear(); + + QString fileName = NodeHelper::instance()->writeNodeToTempFile( msgPart ); + QString href = QString( "attachment:%1?place=body" ).arg( msgPart->index().toString() ); + + QString iconName; + QByteArray contentId = msgPart->index().toString().toUtf8(); + if ( inlineImage ) { + iconName = href; + } + else { + iconName = NodeHelper::instance()->iconName( msgPart ); + if( iconName.right( 14 ) == "mime_empty.png" ) { + NodeHelper::instance()->magicSetType( msgPart ); + iconName = NodeHelper::instance()->iconName( msgPart ); + } + } + + if ( inlineImage ) { + // show the filename of the image below the embedded image + htmlWriter()->queue( "
" + "" + "
" + "" + "
" + comment + "

" ); + } + else { + // show the filename next to the image + htmlWriter()->queue( "" + "
" + comment + "

" ); + } +} + +#define SIG_FRAME_COL_UNDEF 99 +#define SIG_FRAME_COL_RED -1 +#define SIG_FRAME_COL_YELLOW 0 +#define SIG_FRAME_COL_GREEN 1 +QString ObjectTreeParser::sigStatusToString( const Kleo::CryptoBackend::Protocol* cryptProto, + int status_code, + GpgME::Signature::Summary summary, + int& frameColor, + bool& showKeyInfos ) +{ + // note: At the moment frameColor and showKeyInfos are + // used for CMS only but not for PGP signatures + // pending(khz): Implement usage of these for PGP sigs as well. + showKeyInfos = true; + QString result; + if( cryptProto ) { + if( cryptProto == Kleo::CryptoBackendFactory::instance()->openpgp() ) { + // process enum according to it's definition to be read in + // GNU Privacy Guard CVS repository /gpgme/gpgme/gpgme.h + switch( status_code ) { + case 0: // GPGME_SIG_STAT_NONE + result = i18n("Error: Signature not verified"); + break; + case 1: // GPGME_SIG_STAT_GOOD + result = i18n("Good signature"); + break; + case 2: // GPGME_SIG_STAT_BAD + result = i18n("Bad signature"); + break; + case 3: // GPGME_SIG_STAT_NOKEY + result = i18n("No public key to verify the signature"); + break; + case 4: // GPGME_SIG_STAT_NOSIG + result = i18n("No signature found"); + break; + case 5: // GPGME_SIG_STAT_ERROR + result = i18n("Error verifying the signature"); + break; + case 6: // GPGME_SIG_STAT_DIFF + result = i18n("Different results for signatures"); + break; + /* PENDING(khz) Verify exact meaning of the following values: + case 7: // GPGME_SIG_STAT_GOOD_EXP + return i18n("Signature certificate is expired"); + break; + case 8: // GPGME_SIG_STAT_GOOD_EXPKEY + return i18n("One of the certificate's keys is expired"); + break; + */ + default: + result = ""; // do *not* return a default text here ! + break; + } + } + else if ( cryptProto == Kleo::CryptoBackendFactory::instance()->smime() ) { + // process status bits according to SigStatus_... + // definitions in kdenetwork/libkdenetwork/cryptplug.h + + if( summary == GpgME::Signature::None ) { + result = i18n("No status information available."); + frameColor = SIG_FRAME_COL_YELLOW; + showKeyInfos = false; + return result; + } + + if( summary & GpgME::Signature::Valid ) { + result = i18n("Good signature."); + // Note: + // Here we are work differently than KMail did before! + // + // The GOOD case ( == sig matching and the complete + // certificate chain was verified and is valid today ) + // by definition does *not* show any key + // information but just states that things are OK. + // (khz, according to LinuxTag 2002 meeting) + frameColor = SIG_FRAME_COL_GREEN; + showKeyInfos = false; + return result; + } + + // we are still there? OK, let's test the different cases: + + // we assume green, test for yellow or red (in this order!) + frameColor = SIG_FRAME_COL_GREEN; + QString result2; + if( summary & GpgME::Signature::KeyExpired ){ + // still is green! + result2 += i18n("One key has expired."); + } + if( summary & GpgME::Signature::SigExpired ){ + // and still is green! + result2 += i18n("The signature has expired."); + } + + // test for yellow: + if( summary & GpgME::Signature::KeyMissing ) { + result2 += i18n("Unable to verify: key missing."); + // if the signature certificate is missing + // we cannot show information on it + showKeyInfos = false; + frameColor = SIG_FRAME_COL_YELLOW; + } + if( summary & GpgME::Signature::CrlMissing ){ + result2 += i18n("CRL not available."); + frameColor = SIG_FRAME_COL_YELLOW; + } + if( summary & GpgME::Signature::CrlTooOld ){ + result2 += i18n("Available CRL is too old."); + frameColor = SIG_FRAME_COL_YELLOW; + } + if( summary & GpgME::Signature::BadPolicy ){ + result2 += i18n("A policy was not met."); + frameColor = SIG_FRAME_COL_YELLOW; + } + if( summary & GpgME::Signature::SysError ){ + result2 += i18n("A system error occurred."); + // if a system error occurred + // we cannot trust any information + // that was given back by the plug-in + showKeyInfos = false; + frameColor = SIG_FRAME_COL_YELLOW; + } + + // test for red: + if( summary & GpgME::Signature::KeyRevoked ){ + // this is red! + result2 += i18n("One key has been revoked."); + frameColor = SIG_FRAME_COL_RED; + } + if( summary & GpgME::Signature::Red ) { + if( result2.isEmpty() ) + // Note: + // Here we are work differently than KMail did before! + // + // The BAD case ( == sig *not* matching ) + // by definition does *not* show any key + // information but just states that things are BAD. + // + // The reason for this: In this case ALL information + // might be falsificated, we can NOT trust the data + // in the body NOT the signature - so we don't show + // any key/signature information at all! + // (khz, according to LinuxTag 2002 meeting) + showKeyInfos = false; + frameColor = SIG_FRAME_COL_RED; + } + else + result = ""; + + if( SIG_FRAME_COL_GREEN == frameColor ) { + result = i18n("Good signature."); + } else if( SIG_FRAME_COL_RED == frameColor ) { + result = i18n("Bad signature."); + } else + result = ""; + + if( !result2.isEmpty() ) { + if( !result.isEmpty() ) + result.append("
"); + result.append( result2 ); + } + } + /* + // add i18n support for 3rd party plug-ins here: + else if ( cryptPlug->libName().contains( "yetanotherpluginname", Qt::CaseInsensitive )) { + + } + */ + } + return result; +} + + +static QString writeSimpleSigstatHeader( const PartMetaData &block ) +{ +QString html; +html += "
"; + +if ( block.signClass == "signErr" ) { + html += i18n( "Invalid signature." ); +} else if ( block.signClass == "signOkKeyBad" || block.signClass == "signWarn" ) { + html += i18n( "Not enough information to check signature validity." ); +} else if ( block.signClass == "signOkKeyOk" ) { + QString addr; + if ( !block.signerMailAddresses.isEmpty() ) + addr = block.signerMailAddresses.first(); + QString name = addr; + if ( name.isEmpty() ) + name = block.signer; + if ( addr.isEmpty() ) { + html += i18n( "Signature is valid." ); + } else { + html += i18n( "Signed by %2.", addr, name ); + } +} else { + // should not happen + html += i18n( "Unknown signature state" ); +} +html += ""; +html += ""; +html += i18n( "Show Details" ); +html += "
"; +return html; +} + +static QString beginVerboseSigstatHeader() +{ +return ""; +html += "
"; +} + +static QString makeShowAuditLogLink( const GpgME::Error & err, const QString & auditLog ) { +if ( const unsigned int code = err.code() ) { + if ( code == GPG_ERR_NOT_IMPLEMENTED ) { + kDebug() << "makeShowAuditLogLink: not showing link (not implemented)"; + return QString(); + } else if ( code == GPG_ERR_NO_DATA ) { + kDebug() << "makeShowAuditLogLink: not showing link (not available)"; + return i18n("No Audit Log available"); + } else { + return i18n("Error Retrieving Audit Log: %1", QString::fromLocal8Bit( err.asString() ) ); + } +} + +if ( !auditLog.isEmpty() ) { + KUrl url; + url.setProtocol( "kmail" ); + url.setPath( "showAuditLog" ); + url.addQueryItem( "log", auditLog ); + + return "" + i18nc("The Audit Log is a detailed error log from the gnupg backend", "Show Audit Log") + ""; +} + +return QString(); +} + +static QString endVerboseSigstatHeader( const PartMetaData & pmd ) +{ +QString html; +html += ""; +html += ""; +html += i18n( "Hide Details" ); +html += "
"; +html += makeShowAuditLogLink( pmd.auditLogError, pmd.auditLog ); +html += "
"; +return html; +} + +QString ObjectTreeParser::writeSigstatHeader( PartMetaData & block, + const Kleo::CryptoBackend::Protocol * cryptProto, + const QString & fromAddress, + KMime::Content *node ) +{ + const bool isSMIME = cryptProto && ( cryptProto == Kleo::CryptoBackendFactory::instance()->smime() ); + QString signer = block.signer; + + QString htmlStr, simpleHtmlStr; + QString dir = ( QApplication::isRightToLeft() ? "rtl" : "ltr" ); + QString cellPadding("cellpadding=\"1\""); + + if( block.isEncapsulatedRfc822Message ) + { + htmlStr += "" + "
"; + if( node ) { + htmlStr += "" + + i18n("Encapsulated message") + ""; + } else { + htmlStr += i18n("Encapsulated message"); + } + htmlStr += "
"; + } + + if( block.isEncrypted ) { + htmlStr += "" + "
"; + if ( block.inProgress ) { + htmlStr += i18n("Please wait while the message is being decrypted..."); + } else if( block.isDecryptable ) { + htmlStr += i18n("Encrypted message"); + } else { + htmlStr += i18n("Encrypted message (decryption not possible)"); + if( !block.errorText.isEmpty() ) { + htmlStr += "
" + i18n("Reason: %1", block.errorText ); + } + } + htmlStr += "
"; + } + + if ( block.isSigned && block.inProgress ) { + block.signClass = "signInProgress"; + htmlStr += "" + "
"; + htmlStr += i18n("Please wait while the signature is being verified..."); + htmlStr += "
"; + } + + simpleHtmlStr = htmlStr; + + if( block.isSigned && !block.inProgress ) { + QStringList& blockAddrs( block.signerMailAddresses ); + // note: At the moment frameColor and showKeyInfos are + // used for CMS only but not for PGP signatures + // pending(khz): Implement usage of these for PGP sigs as well. + int frameColor = SIG_FRAME_COL_UNDEF; + bool showKeyInfos; + bool onlyShowKeyURL = false; + bool cannotCheckSignature = true; + QString statusStr = sigStatusToString( cryptProto, + block.status_code, + block.sigSummary, + frameColor, + showKeyInfos ); + // if needed fallback to english status text + // that was reported by the plugin + if( statusStr.isEmpty() ) + statusStr = block.status; + if( block.technicalProblem ) + frameColor = SIG_FRAME_COL_YELLOW; + + switch( frameColor ){ + case SIG_FRAME_COL_RED: + cannotCheckSignature = false; + break; + case SIG_FRAME_COL_YELLOW: + cannotCheckSignature = true; + break; + case SIG_FRAME_COL_GREEN: + cannotCheckSignature = false; + break; + } + + // compose the string for displaying the key ID + // either as URL or not linked (for PGP) + // note: Once we can start PGP key manager programs + // from within KMail we could change this and + // always show the URL. (khz, 2002/06/27) + QString startKeyHREF; + if( isSMIME ) + startKeyHREF = + QString("") + .arg( cryptProto->displayName(), + cryptProto->name(), + QString::fromLatin1( block.keyId ) ); + QString keyWithWithoutURL + // FIXME: Kleopatra misses a -query option, so disable this for now. + = /*isSMIME + ? QString("%1%2") + .arg( startKeyHREF, + cannotCheckSignature ? i18n("[Details]") : ("0x" + block.keyId) ) + : */"0x" + QString::fromUtf8( block.keyId ); + + + // temporary hack: always show key information! + showKeyInfos = true; + + // Sorry for using 'black' as null color but .isValid() + // checking with QColor default c'tor did not work for + // some reason. + if( isSMIME && (SIG_FRAME_COL_UNDEF != frameColor) ) { + + // new frame settings for CMS: + // beautify the status string + if( !statusStr.isEmpty() ) { + statusStr.prepend(""); + statusStr.append( ""); + } + + // special color handling: S/MIME uses only green/yellow/red. + switch( frameColor ) { + case SIG_FRAME_COL_RED: + block.signClass = "signErr";//"signCMSRed"; + onlyShowKeyURL = true; + break; + case SIG_FRAME_COL_YELLOW: + if( block.technicalProblem ) + block.signClass = "signWarn"; + else + block.signClass = "signOkKeyBad";//"signCMSYellow"; + break; + case SIG_FRAME_COL_GREEN: + block.signClass = "signOkKeyOk";//"signCMSGreen"; + // extra hint for green case + // that email addresses in DN do not match fromAddress + QString greenCaseWarning; + QString msgFrom( KPIMUtils::extractEmailAddress(fromAddress) ); + QString certificate; + if( block.keyId.isEmpty() ) + certificate = i18n("certificate"); + else + certificate = startKeyHREF + i18n("certificate") + ""; + if( !blockAddrs.empty() ){ + if( !blockAddrs.contains( msgFrom, Qt::CaseInsensitive ) ) { + greenCaseWarning = + "" + + i18nc("Start of warning message." + ,"Warning:") + + " " + + i18n("Sender's mail address is not stored " + "in the %1 used for signing.", certificate) + + "
" + + i18n("sender: ") + + msgFrom + + "
" + + i18n("stored: "); + // We cannot use Qt's join() function here but + // have to join the addresses manually to + // extract the mail addresses (without '<''>') + // before including it into our string: + bool bStart = true; + for(QStringList::ConstIterator it = blockAddrs.constBegin(); + it != blockAddrs.constEnd(); ++it ){ + if( !bStart ) + greenCaseWarning.append(",
   "); + bStart = false; + greenCaseWarning.append( KPIMUtils::extractEmailAddress(*it) ); + } + } + } else { + greenCaseWarning = + "" + + i18nc("Start of warning message.","Warning:") + + " " + + i18n("No mail address is stored in the %1 used for signing, " + "so we cannot compare it to the sender's address %2.", + certificate, + msgFrom); + } + if( !greenCaseWarning.isEmpty() ) { + if( !statusStr.isEmpty() ) + statusStr.append("
 
"); + statusStr.append( greenCaseWarning ); + } + break; + } + + QString frame = "" + "
"; + htmlStr += frame + beginVerboseSigstatHeader(); + simpleHtmlStr += frame; + simpleHtmlStr += writeSimpleSigstatHeader( block ); + if( block.technicalProblem ) { + htmlStr += block.errorText; + } + else if( showKeyInfos ) { + if( cannotCheckSignature ) { + htmlStr += i18n( "Not enough information to check " + "signature. %1", + keyWithWithoutURL ); + } + else { + + if (block.signer.isEmpty()) + signer = ""; + else { + if( !blockAddrs.empty() ){ + QString address = StringUtil::encodeMailtoUrl( blockAddrs.first() ); + signer = "" + signer + ""; + } + } + + if( block.keyId.isEmpty() ) { + if( signer.isEmpty() || onlyShowKeyURL ) + htmlStr += i18n( "Message was signed with unknown key." ); + else + htmlStr += i18n( "Message was signed by %1.", + signer ); + } else { + QDateTime created = block.creationTime; + if( created.isValid() ) { + if( signer.isEmpty() ) { + if( onlyShowKeyURL ) + htmlStr += i18n( "Message was signed with key %1.", + keyWithWithoutURL ); + else + htmlStr += i18n( "Message was signed on %1 with key %2.", + KGlobal::locale()->formatDateTime( created ), + keyWithWithoutURL ); + } + else { + if( onlyShowKeyURL ) + htmlStr += i18n( "Message was signed with key %1.", + keyWithWithoutURL ); + else + htmlStr += i18n( "Message was signed by %3 on %1 with key %2", + KGlobal::locale()->formatDateTime( created ), + keyWithWithoutURL, + signer ); + } + } + else { + if( signer.isEmpty() || onlyShowKeyURL ) + htmlStr += i18n( "Message was signed with key %1.", + keyWithWithoutURL ); + else + htmlStr += i18n( "Message was signed by %2 with key %1.", + keyWithWithoutURL, + signer ); + } + } + } + htmlStr += "
"; + if( !statusStr.isEmpty() ) { + htmlStr += " 
"; + htmlStr += i18n( "Status: " ); + htmlStr += statusStr; + } + } else { + htmlStr += statusStr; + } + frame = "
"; + htmlStr += endVerboseSigstatHeader( block ) + frame; + simpleHtmlStr += frame; + + } else { + + // old frame settings for PGP: + + if( block.signer.isEmpty() || block.technicalProblem ) { + block.signClass = "signWarn"; + QString frame = "" + "
"; + htmlStr += frame + beginVerboseSigstatHeader(); + simpleHtmlStr += frame; + simpleHtmlStr += writeSimpleSigstatHeader( block ); + if( block.technicalProblem ) { + htmlStr += block.errorText; + } + else { + if( !block.keyId.isEmpty() ) { + QDateTime created = block.creationTime; + if ( created.isValid() ) + htmlStr += i18n( "Message was signed on %1 with unknown key %2.", + KGlobal::locale()->formatDateTime( created ), + keyWithWithoutURL ); + else + htmlStr += i18n( "Message was signed with unknown key %1.", + keyWithWithoutURL ); + } + else + htmlStr += i18n( "Message was signed with unknown key." ); + htmlStr += "
"; + htmlStr += i18n( "The validity of the signature cannot be " + "verified." ); + if( !statusStr.isEmpty() ) { + htmlStr += "
"; + htmlStr += i18n( "Status: " ); + htmlStr += ""; + htmlStr += statusStr; + htmlStr += ""; + } + } + frame = "
"; + htmlStr += endVerboseSigstatHeader( block ) + frame; + simpleHtmlStr += frame; + } + else + { + // HTMLize the signer's user id and create mailto: link + signer = StringUtil::quoteHtmlChars( signer, true ); + signer = "" + signer + ""; + + if (block.isGoodSignature) { + if( block.keyTrust < Kpgp::KPGP_VALIDITY_MARGINAL ) + block.signClass = "signOkKeyBad"; + else + block.signClass = "signOkKeyOk"; + QString frame = "" + "" + "
"; + htmlStr += frame + beginVerboseSigstatHeader(); + simpleHtmlStr += frame; + simpleHtmlStr += writeSimpleSigstatHeader( block ); + if( !block.keyId.isEmpty() ) + htmlStr += i18n( "Message was signed by %2 (Key ID: %1).", + keyWithWithoutURL, + signer ); + else + htmlStr += i18n( "Message was signed by %1.", signer ); + htmlStr += "
"; + + switch( block.keyTrust ) + { + case Kpgp::KPGP_VALIDITY_UNKNOWN: + htmlStr += i18n( "The signature is valid, but the key's " + "validity is unknown." ); + break; + case Kpgp::KPGP_VALIDITY_MARGINAL: + htmlStr += i18n( "The signature is valid and the key is " + "marginally trusted." ); + break; + case Kpgp::KPGP_VALIDITY_FULL: + htmlStr += i18n( "The signature is valid and the key is " + "fully trusted." ); + break; + case Kpgp::KPGP_VALIDITY_ULTIMATE: + htmlStr += i18n( "The signature is valid and the key is " + "ultimately trusted." ); + break; + default: + htmlStr += i18n( "The signature is valid, but the key is " + "untrusted." ); + } + frame = "
"; + htmlStr += endVerboseSigstatHeader( block ) + frame; + simpleHtmlStr += frame; + } + else + { + block.signClass = "signErr"; + QString frame = "" + "" + ""; + htmlStr += "
"; + htmlStr += frame + beginVerboseSigstatHeader(); + simpleHtmlStr += frame; + simpleHtmlStr += writeSimpleSigstatHeader( block ); + if( !block.keyId.isEmpty() ) + htmlStr += i18n( "Message was signed by %2 (Key ID: %1).", + keyWithWithoutURL, + signer ); + else + htmlStr += i18n( "Message was signed by %1.", signer ); + htmlStr += "
"; + htmlStr += i18n("Warning: The signature is bad."); + frame = "
"; + htmlStr += endVerboseSigstatHeader( block ) + frame; + simpleHtmlStr += frame; + } + } + } + } + + if ( mSource->showSignatureDetails() ) + return htmlStr; + return simpleHtmlStr; +} + +QString ObjectTreeParser::writeSigstatFooter( PartMetaData& block ) +{ + QString dir = ( QApplication::isRightToLeft() ? "rtl" : "ltr" ); + + QString htmlStr; + + if (block.isSigned) { + htmlStr += "
" + + i18n( "End of signed message" ) + + "
"; + } + + if (block.isEncrypted) { + htmlStr += "
" + + i18n( "End of encrypted message" ) + + "
"; + } + + if( block.isEncapsulatedRfc822Message ) + { + htmlStr += "
" + + i18n( "End of encapsulated message" ) + + "
"; + } + + return htmlStr; +} + + +//----------------------------------------------------------------------------- + +void ObjectTreeParser::writeAttachmentMarkHeader( KMime::Content *node ) +{ + if ( !mHtmlWriter ) + return; + + htmlWriter()->queue( QString( "
\n" ).arg( node->index().toString() ) ); +} + +//----------------------------------------------------------------------------- + +void ObjectTreeParser::writeAttachmentMarkFooter() +{ + if ( !mHtmlWriter ) + return; + + htmlWriter()->queue( QString( "
" ) ); +} + + + +//----------------------------------------------------------------------------- +void ObjectTreeParser::writeBodyStr( const QByteArray& aStr, const QTextCodec *aCodec, + const QString& fromAddress ) +{ + KMMsgSignatureState dummy1; + KMMsgEncryptionState dummy2; + writeBodyStr( aStr, aCodec, fromAddress, dummy1, dummy2, false ); +} + +//----------------------------------------------------------------------------- +void ObjectTreeParser::writeBodyStr( const QByteArray& aStr, const QTextCodec *aCodec, + const QString& fromAddress, + KMMsgSignatureState& inlineSignatureState, + KMMsgEncryptionState& inlineEncryptionState, + bool decorate ) +{ + bool goodSignature = false; + Kpgp::Module* pgp = Kpgp::Module::getKpgp(); + assert(pgp != 0); + bool isPgpMessage = false; // true if the message contains at least one + // PGP MESSAGE or one PGP SIGNED MESSAGE block + QString dir = ( QApplication::isRightToLeft() ? "rtl" : "ltr" ); + QString headerStr = QString("
").arg(dir); + + inlineSignatureState = KMMsgNotSigned; + inlineEncryptionState = KMMsgNotEncrypted; + QList pgpBlocks; + QList nonPgpBlocks; + if( Kpgp::Module::prepareMessageForDecryption( aStr, pgpBlocks, nonPgpBlocks ) ) + { + bool isEncrypted = false, isSigned = false; + bool fullySignedOrEncrypted = true; + bool firstNonPgpBlock = true; + bool couldDecrypt = false; + QString signer; + QByteArray keyId; + QString decryptionError; + Kpgp::Validity keyTrust = Kpgp::KPGP_VALIDITY_FULL; + + QList::iterator pbit = pgpBlocks.begin(); + QListIterator npbit( nonPgpBlocks ); + QString htmlStr; + for( ; pbit != pgpBlocks.end(); ++pbit ) + { + // insert the next Non-OpenPGP block + QByteArray str( npbit.next() ); + if( !str.isEmpty() ) { + htmlStr += quotedHTML( aCodec->toUnicode( str ), decorate ); + kDebug() << "Non-empty Non-OpenPGP block found: '" << str << "'"; + // treat messages with empty lines before the first clearsigned + // block as fully signed/encrypted + if( firstNonPgpBlock ) { + // check whether str only consists of \n + for( QByteArray::ConstIterator c = str.begin(); *c; ++c ) { + if( *c != '\n' ) { + fullySignedOrEncrypted = false; + break; + } + } + } + else { + fullySignedOrEncrypted = false; + } + } + firstNonPgpBlock = false; + + //htmlStr += "
"; + + Kpgp::Block &block = *pbit; + if( ( block.type() == Kpgp::PgpMessageBlock /*FIXME(Andras) port to akonadi + && + // ### Workaround for bug 56693 + !kmkernel->contextMenuShown() */) || + ( block.type() == Kpgp::ClearsignedBlock ) ) + { + isPgpMessage = true; + if( block.type() == Kpgp::PgpMessageBlock ) + { + mSource->emitNoDrag(); + // try to decrypt this OpenPGP block + couldDecrypt = block.decrypt(); + isEncrypted = block.isEncrypted(); + if (!couldDecrypt) { + decryptionError = pgp->lastErrorMsg(); + } + } + else + { + // try to verify this OpenPGP block + block.verify(); + } + + isSigned = block.isSigned(); + if( isSigned ) + { + keyId = block.signatureKeyId(); + signer = block.signatureUserId(); + if( !signer.isEmpty() ) + { + goodSignature = block.goodSignature(); + + if( !keyId.isEmpty() ) { + keyTrust = pgp->keyTrust( keyId ); + Kpgp::Key* key = pgp->publicKey( keyId ); + if ( key ) { + // Use the user ID from the key because this one + // is charset safe. + signer = key->primaryUserID(); + } + } + else + // This is needed for the PGP 6 support because PGP 6 doesn't + // print the key id of the signing key if the key is known. + keyTrust = pgp->keyTrust( signer ); + } + } + + if( isSigned ) + inlineSignatureState = KMMsgPartiallySigned; + if( isEncrypted ) + inlineEncryptionState = KMMsgPartiallyEncrypted; + + PartMetaData messagePart; + + messagePart.isSigned = isSigned; + messagePart.technicalProblem = false; + messagePart.isGoodSignature = goodSignature; + messagePart.isEncrypted = isEncrypted; + messagePart.isDecryptable = couldDecrypt; + messagePart.decryptionError = decryptionError; + messagePart.signer = signer; + messagePart.keyId = keyId; + messagePart.keyTrust = keyTrust; + messagePart.auditLogError = GpgME::Error( GPG_ERR_NOT_IMPLEMENTED ); + + htmlStr += writeSigstatHeader( messagePart, 0, fromAddress ); + + if ( couldDecrypt || !isEncrypted ) { + htmlStr += quotedHTML( aCodec->toUnicode( block.text() ), decorate ); + } + else { + htmlStr += QString( "
%1
" ) + .arg( i18n( "The message could not be decrypted.") ); + } + htmlStr += writeSigstatFooter( messagePart ); + } + else // block is neither message block nor clearsigned block + htmlStr += quotedHTML( aCodec->toUnicode( block.text() ), + decorate ); + } + + // add the last Non-OpenPGP block + QByteArray str( nonPgpBlocks.last() ); + if( !str.isEmpty() ) { + htmlStr += quotedHTML( aCodec->toUnicode( str ), decorate ); + // Even if the trailing Non-OpenPGP block isn't empty we still + // consider the message part fully signed/encrypted because else + // all inline signed mailing list messages would only be partially + // signed because of the footer which is often added by the mailing + // list software. IK, 2003-02-15 + } + if( fullySignedOrEncrypted ) { + if( inlineSignatureState == KMMsgPartiallySigned ) + inlineSignatureState = KMMsgFullySigned; + if( inlineEncryptionState == KMMsgPartiallyEncrypted ) + inlineEncryptionState = KMMsgFullyEncrypted; + } + htmlWriter()->queue( htmlStr ); + } + else + htmlWriter()->queue( quotedHTML( aCodec->toUnicode( aStr ), decorate ) ); +} + + +QString ObjectTreeParser::quotedHTML( const QString& s, bool decorate ) +{ + assert( cssHelper() ); + + int convertFlags = LinkLocator::PreserveSpaces | LinkLocator::HighlightText; + if ( decorate && GlobalSettings::self()->showEmoticons() ) { + convertFlags |= LinkLocator::ReplaceSmileys; + } + QString htmlStr; + const QString normalStartTag = cssHelper()->nonQuotedFontTag(); + QString quoteFontTag[3]; + QString deepQuoteFontTag[3]; + for ( int i = 0 ; i < 3 ; ++i ) { + quoteFontTag[i] = cssHelper()->quoteFontTag( i ); + deepQuoteFontTag[i] = cssHelper()->quoteFontTag( i+3 ); + } + const QString normalEndTag = "
"; + const QString quoteEnd = ""; + + const unsigned int length = s.length(); + bool paraIsRTL = false; + bool startNewPara = true; + unsigned int pos, beg; + + // skip leading empty lines + for ( pos = 0; pos < length && s[pos] <= ' '; pos++ ) + ; + while (pos > 0 && (s[pos-1] == ' ' || s[pos-1] == '\t')) pos--; + beg = pos; + + int currQuoteLevel = -2; // -2 == no previous lines + bool curHidden = false; // no hide any block + + if ( GlobalSettings::self()->showExpandQuotesMark() ) + { + // Cache Icons + if ( mCollapseIcon.isEmpty() ) { + mCollapseIcon= LinkLocator::pngToDataUrl( + IconNameCache::instance()->iconPath( "quotecollapse", 0 )); + } + if ( mExpandIcon.isEmpty() ) + mExpandIcon= LinkLocator::pngToDataUrl( + IconNameCache::instance()->iconPath( "quoteexpand", 0 )); + } + + while (beg': + case '|': + actQuoteLevel++; + break; + case ' ': // spaces and tabs are allowed between the quote markers + case '\t': + case '\r': + break; + default: // stop quoting depth calculation + p = line.length(); + break; + } + } /* for() */ + + bool actHidden = false; + QString textExpand; + + // This quoted line needs be hidden + if (GlobalSettings::self()->showExpandQuotesMark() && mSource->levelQuote() >= 0 + && mSource->levelQuote() <= ( actQuoteLevel ) ) + actHidden = true; + + if ( actQuoteLevel != currQuoteLevel ) { + /* finish last quotelevel */ + if (currQuoteLevel == -1) + htmlStr.append( normalEndTag ); + else if ( currQuoteLevel >= 0 && !curHidden ) + htmlStr.append( quoteEnd ); + + /* start new quotelevel */ + if (actQuoteLevel == -1) + htmlStr += normalStartTag; + else + { + if ( GlobalSettings::self()->showExpandQuotesMark() ) + if (true) + { + if ( actHidden ) + { + //only show the QuoteMark when is the first line of the level hidden + if ( !curHidden ) + { + //Expand all quotes + htmlStr += "
" ; + htmlStr += QString( "" + "\"\"" ) + .arg(-1) + .arg( mExpandIcon ); + htmlStr += "

"; + htmlStr += quoteEnd; + } + }else { + htmlStr += "
" ; + htmlStr += QString( "" + "\"\"" ) + .arg(actQuoteLevel) + .arg( mCollapseIcon); + htmlStr += "
"; + if ( actQuoteLevel < 3 ) + htmlStr += quoteFontTag[actQuoteLevel]; + else + htmlStr += deepQuoteFontTag[actQuoteLevel%3]; + } + } else + if ( actQuoteLevel < 3 ) + htmlStr += quoteFontTag[actQuoteLevel]; + else + htmlStr += deepQuoteFontTag[actQuoteLevel%3]; + } + currQuoteLevel = actQuoteLevel; + } + curHidden = actHidden; + + + if ( !actHidden ) + { + // don't write empty
blocks (they have zero height) + // ignore ^M DOS linebreaks + if( !line.remove( '\015' ).isEmpty() ) + { + if ( startNewPara ) + paraIsRTL = line.isRightToLeft(); + htmlStr += QString( "
" ).arg( paraIsRTL ? "rtl" : "ltr" ); + htmlStr += LinkLocator::convertToHtml( line, convertFlags ); + htmlStr += QString( "
" ); + startNewPara = looksLikeParaBreak( s, pos ); + } + else + { + htmlStr += "
"; + // after an empty line, always start a new paragraph + startNewPara = true; + } + } + } /* while() */ + + /* really finish the last quotelevel */ + if (currQuoteLevel == -1) + htmlStr.append( normalEndTag ); + else + htmlStr.append( quoteEnd ); + + //kDebug() << "========================================\n" + // << htmlStr + // << "\n======================================\n"; + return htmlStr; +} + + + +const QTextCodec * ObjectTreeParser::codecFor( KMime::Content * node ) const +{ + assert( node ); + if ( mSource->overrideCodec() ) + return mSource->overrideCodec(); + return NodeHelper::instance()->codec( node ); +} + +// Guesstimate if the newline at newLinePos actually separates paragraphs in the text s +// We use several heuristics: +// 1. If newLinePos points after or before (=at the very beginning of) text, it is not between paragraphs +// 2. If the previous line was longer than the wrap size, we want to consider it a paragraph on its own +// (some clients, notably Outlook, send each para as a line in the plain-text version). +// 3. Otherwise, we check if the newline could have been inserted for wrapping around; if this +// was the case, then the previous line will be shorter than the wrap size (which we already +// know because of item 2 above), but adding the first word from the next line will make it +// longer than the wrap size. +bool ObjectTreeParser::looksLikeParaBreak( const QString& s, unsigned int newLinePos ) const +{ + const unsigned int WRAP_COL = 78; + + unsigned int length = s.length(); + // 1. Is newLinePos at an end of the text? + if ( newLinePos >= length-1 || newLinePos == 0 ) { + return false; + } + + // 2. Is the previous line really a paragraph -- longer than the wrap size? + + // First char of prev line -- works also for first line + unsigned prevStart = s.lastIndexOf( '\n', newLinePos - 1 ) + 1; + unsigned prevLineLength = newLinePos - prevStart; + if ( prevLineLength > WRAP_COL ) { + return true; + } + + // find next line to delimit search for first word + unsigned int nextStart = newLinePos + 1; + int nextEnd = s.indexOf( '\n', nextStart ); + if ( nextEnd == -1 ) { + nextEnd = length; + } + QString nextLine = s.mid( nextStart, nextEnd - nextStart ); + length = nextLine.length(); + // search for first word in next line + unsigned int wordStart; + bool found = false; + for ( wordStart = 0; !found && wordStart < length; wordStart++ ) { + switch ( nextLine[wordStart].toLatin1() ) { + case '>': + case '|': + case ' ': // spaces, tabs and quote markers don't count + case '\t': + case '\r': + break; + default: + found = true; + break; + } + } /* for() */ + + if ( !found ) { + // next line is essentially empty, it seems -- empty lines are + // para separators + return true; + } + //Find end of first word. + //Note: flowText (in kmmessage.cpp) separates words for wrap by + //spaces only. This should be consistent, which calls for some + //refactoring. + int wordEnd = nextLine.indexOf( ' ', wordStart ); + if ( wordEnd == (-1) ) { + wordEnd = length; + } + int wordLength = wordEnd - wordStart; + + // 3. If adding a space and the first word to the prev line don't + // make it reach the wrap column, then the break was probably + // meaningful + return prevLineLength + wordLength + 1 < WRAP_COL; +} + +#ifdef MARCS_DEBUG +void ObjectTreeParser::dumpToFile( const char * filename, const char * start, + size_t len ) { + assert( filename ); + + QFile f( filename ); + if ( f.open( QIODevice::WriteOnly ) ) { + if ( start ) { + QDataStream ds( &f ); + ds.writeRawData( start, len ); + } + f.close(); // If data is 0 we just create a zero length file. + } +} +#endif // !NDEBUG + + +KMime::Content* ObjectTreeParser::findType( KMime::Content* content, const QByteArray& mimeType, bool deep, bool wide ) +{ + if( ( !content->contentType()->isEmpty() ) + && ( mimeType.isEmpty() || ( mimeType == content->contentType()->mimeType() ) ) ) + return content; + KMime::Content *child = NodeHelper::firstChild( content ); + if ( child && deep ) //first child + return findType( child, mimeType, deep, wide ); + + KMime::Content *next = NodeHelper::nextSibling( content ); + if (next && wide ) //next on the same level + return findType( next, mimeType, deep, wide ); + + return 0; +} + +KMime::Content* ObjectTreeParser::findTypeNot( KMime::Content * content, const QByteArray& mediaType, const QByteArray& subType, bool deep, bool wide ) +{ + if( ( !content->contentType()->isEmpty() ) + && ( mediaType.isEmpty() || content->contentType()->mediaType() != mediaType ) + && ( subType.isEmpty() || content->contentType()->subType() != subType ) + ) + return content; + KMime::Content *child = NodeHelper::firstChild( content ); + if ( child && deep ) + return findTypeNot( child, mediaType, subType, deep, wide ); + + KMime::Content *next = NodeHelper::nextSibling( content ); + if ( next && wide ) + return findTypeNot( next, mediaType, subType, deep, wide ); + return 0; +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeparser.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeparser.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeparser.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeparser.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,360 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + objecttreeparser.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + Copyright (C) 2002-2003, 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef _MESSAGEVIEWER_OBJECTTREEPARSER_H_ +#define _MESSAGEVIEWER_OBJECTTREEPARSER_H_ + +#include +#include + +#include + +#include "nodehelper.h" + +class QString; + +namespace KMime { + class Content; +} + +namespace GpgME { + class Error; +} + +class PartMetaData; + +namespace MessageViewer { + +class ViewerPrivate; +class HtmlWriter; +class CSSHelper; +class AttachmentStrategy; +class ObjectTreeSourceIf; + + +class ProcessResult { +public: + explicit ProcessResult( KMMsgSignatureState inlineSignatureState = KMMsgNotSigned, + KMMsgEncryptionState inlineEncryptionState = KMMsgNotEncrypted, + bool neverDisplayInline = false, + bool isImage = false ) + : mInlineSignatureState( inlineSignatureState ), + mInlineEncryptionState( inlineEncryptionState ), + mNeverDisplayInline( neverDisplayInline ), + mIsImage( isImage ) {} + + KMMsgSignatureState inlineSignatureState() const { + return mInlineSignatureState; + } + void setInlineSignatureState( KMMsgSignatureState state ) { + mInlineSignatureState = state; + } + + KMMsgEncryptionState inlineEncryptionState() const { + return mInlineEncryptionState; + } + void setInlineEncryptionState( KMMsgEncryptionState state ) { + mInlineEncryptionState = state; + } + + bool neverDisplayInline() const { return mNeverDisplayInline; } + void setNeverDisplayInline( bool display ) { + mNeverDisplayInline = display; + } + + bool isImage() const { return mIsImage; } + void setIsImage( bool image ) { + mIsImage = image; + } + + void adjustCryptoStatesOfNode( KMime::Content * node ) const; + +private: + KMMsgSignatureState mInlineSignatureState; + KMMsgEncryptionState mInlineEncryptionState; + bool mNeverDisplayInline : 1; + bool mIsImage : 1; +}; + + +class ObjectTreeParser { + class CryptoProtocolSaver; + /** Internal. Copies the context of @p other, but not it's rawReplyString() */ + ObjectTreeParser( const ObjectTreeParser & other ); +public: + explicit ObjectTreeParser( ObjectTreeSourceIf *source, const Kleo::CryptoBackend::Protocol * protocol=0, + bool showOneMimePart=false, bool keepEncryptions=false, + bool includeSignatures=true, + const AttachmentStrategy * attachmentStrategy=0, + HtmlWriter * htmlWriter=0, + CSSHelper * cssHelper=0 ); + virtual ~ObjectTreeParser(); + + void setAllowAsync( bool allow ) { assert( !mHasPendingAsyncJobs ); mAllowAsync = allow; } + bool allowAsync() const { return mAllowAsync; } + + bool hasPendingAsyncJobs() const { return mHasPendingAsyncJobs; } + + QByteArray rawReplyString() const { return mRawReplyString; } + + /*! @return the text of the message, ie. what would appear in the + composer's text editor if this was edited. */ + QString textualContent() const { return mTextualContent; } + + QByteArray textualContentCharset() const { return mTextualContentCharset; } + + void setCryptoProtocol( const Kleo::CryptoBackend::Protocol * protocol ) { + mCryptoProtocol = protocol; + } + const Kleo::CryptoBackend::Protocol* cryptoProtocol() const { + return mCryptoProtocol; + } + + bool showOnlyOneMimePart() const { return mShowOnlyOneMimePart; } + void setShowOnlyOneMimePart( bool show ) { + mShowOnlyOneMimePart = show; + } + + bool keepEncryptions() const { return mKeepEncryptions; } + void setKeepEncryptions( bool keep ) { + mKeepEncryptions = keep; + } + + bool includeSignatures() const { return mIncludeSignatures; } + void setIncludeSignatures( bool include ) { + mIncludeSignatures = include; + } + + const AttachmentStrategy * attachmentStrategy() const { + return mAttachmentStrategy; + } + + HtmlWriter * htmlWriter() const { return mHtmlWriter; } + + CSSHelper * cssHelper() const { return mCSSHelper; } + + /** Parse beginning at a given node and recursively parsing + the children of that node and it's next sibling. */ + // Function is called internally by "parseMsg(KMMessage* msg)" + // and it will be replaced once KMime is alive. + void parseObjectTree( KMime::Content * node ); + +private: + /** Standard children handling a.k.a. multipart/mixed (w/o + kroupware hacks) */ + void stdChildHandling( KMime::Content * child ); + + void defaultHandling( KMime::Content * node, ProcessResult & result ); + + /** 1. Create a new partNode using 'content' data and Content-Description + found in 'cntDesc'. + 2. Make this node the child of 'node'. + 3. Insert the respective entries in the Mime Tree Viewer. + 3. Parse the 'node' to display the content. + + @param addToTextualContent If true, this will add the textual content of the parsed node + to the textual content of the current object tree parser. + Setting this to false is useful for encapsulated messages, as we + do not want the text in those to appear in the editor + + */ + // Function will be replaced once KMime is alive. + void insertAndParseNewChildNode( KMime::Content & node, + const char * content, + const char * cntDesc, + bool append=false, + bool addToTextualContent = true ); + /** if data is 0: + Feeds the HTML widget with the contents of the opaque signed + data found in partNode 'sign'. + if data is set: + Feeds the HTML widget with the contents of the given + multipart/signed object. + Signature is tested. May contain body parts. + + Returns whether a signature was found or not: use this to + find out if opaque data is signed or not. */ + bool writeOpaqueOrMultipartSignedData( KMime::Content * data, + KMime::Content & sign, + const QString & fromAddress, + bool doCheck=true, + QByteArray * cleartextData=0, + const std::vector & paramSignatures = std::vector(), + bool hideErrors=false ); + + /** Writes out the block that we use when the node is encrypted, + but we're deferring decryption for later. */ + void writeDeferredDecryptionBlock(); + + /** Writes out the block that we use when the node is encrypted, + but we've just kicked off async decryption. */ + void writeDecryptionInProgressBlock(); + + + /** Returns the contents of the given multipart/encrypted + object. Data is decypted. May contain body parts. */ + bool okDecryptMIME( KMime::Content& data, + QByteArray& decryptedData, + bool& signatureFound, + std::vector &signatures, + bool showWarning, + bool& passphraseError, + bool& actuallyEncrypted, + bool& decryptionStarted, + QString& aErrorText, + GpgME::Error & auditLogError, + QString& auditLog ); + + bool processMailmanMessage( KMime::Content* node ); + + /** Checks whether @p str contains external references. To be precise, + we only check whether @p str contains 'xxx="http[s]:' where xxx is + not href. Obfuscated external references are ignored on purpose. + */ + static bool containsExternalReferences( const QString & str ); + +public:// (during refactoring) + + bool processTextHtmlSubtype( KMime::Content * node, ProcessResult & result ); + bool processTextPlainSubtype( KMime::Content *node, ProcessResult & result ); + + bool processMultiPartMixedSubtype( KMime::Content * node, ProcessResult & result ); + bool processMultiPartAlternativeSubtype( KMime::Content * node, ProcessResult & result ); + bool processMultiPartDigestSubtype( KMime::Content * node, ProcessResult & result ); + bool processMultiPartParallelSubtype( KMime::Content * node, ProcessResult & result ); + bool processMultiPartSignedSubtype( KMime::Content * node, ProcessResult & result ); + bool processMultiPartEncryptedSubtype( KMime::Content * node, ProcessResult & result ); + + bool processMessageRfc822Subtype( KMime::Content * node, ProcessResult & result ); + + bool processApplicationOctetStreamSubtype( KMime::Content * node, ProcessResult & result ); + bool processApplicationPkcs7MimeSubtype( KMime::Content * node, ProcessResult & result ); + bool processApplicationChiasmusTextSubtype( KMime::Content * node, ProcessResult & result ); + bool processApplicationMsTnefSubtype( KMime::Content *node, ProcessResult &result ); + + bool decryptChiasmus( const QByteArray& data, QByteArray& bodyDecoded, QString& errorText ); + void writeBodyString( const QByteArray & bodyString, + const QString & fromAddress, + const QTextCodec * codec, + ProcessResult & result, bool decorate ); + + void writePartIcon( KMime::Content * msgPart, bool inlineImage = false ); + + QString sigStatusToString( const Kleo::CryptoBackend::Protocol * cryptProto, + int status_code, + GpgME::Signature::Summary summary, + int & frameColor, + bool & showKeyInfos ); + QString writeSigstatHeader( PartMetaData & part, + const Kleo::CryptoBackend::Protocol * cryptProto, + const QString & fromAddress, + KMime::Content *node = 0); + QString writeSigstatFooter( PartMetaData & part ); + + // The attachment mark is a div that is placed around the attchment. It is used for drawing + // a yellow border around the attachment when scrolling to it. When scrolling to it, the border + // color of the div is changed, see KMReaderWin::scrollToAttachment(). + void writeAttachmentMarkHeader( KMime::Content *node ); + void writeAttachmentMarkFooter(); + + void writeBodyStr( const QByteArray & bodyString, + const QTextCodec * aCodec, + const QString & fromAddress, + KMMsgSignatureState & inlineSignatureState, + KMMsgEncryptionState & inlineEncryptionState, + bool decorate ); + + bool isMailmanMessage( KMime::Content * curNode ); + +public: // KMReaderWin still needs this... + void writeBodyStr( const QByteArray & bodyString, + const QTextCodec * aCodec, + const QString & fromAddress ); + static KMime::Content* findType( KMime::Content* content, const QByteArray& mimeType, bool deep, bool wide ); + static KMime::Content* findTypeNot( KMime::Content* content, const QByteArray& mediaType, const QByteArray& subType, bool deep=true, bool wide=true ); + + +private: + /** Change the string to `quoted' html (meaning, that the quoted + part of the message get italized */ + QString quotedHTML(const QString& pos, bool decorate); + + const QTextCodec * codecFor( KMime::Content * node ) const; + /** Check if the newline at position @p newLinePos in string @p s + seems to separate two paragraphs (important for correct BiDi + behavior, but is heuristic because paragraphs are not + well-defined) */ + bool looksLikeParaBreak(const QString& s, unsigned int newLinePos) const; + +#ifdef MARCS_DEBUG + void dumpToFile( const char * filename, const char * dataStart, size_t dataLen ); +#else + void dumpToFile( const char *, const char *, size_t ) {} +#endif + +private: + ObjectTreeSourceIf* mSource; + QByteArray mRawReplyString; + QByteArray mTextualContentCharset; + QString mTextualContent; + const Kleo::CryptoBackend::Protocol * mCryptoProtocol; + + /// Show only one mime part means that the user has selected some node in the message structure + /// viewer that is not the root, which means the user wants to only see the selected node and its + /// children. If that is the case, this variable is set to true. + /// The code needs to behave differently if this is set. For example, it should not process the + /// siblings. Also, consider inline images: Normally, those nodes are completely hidden, as the + /// HTML node embedds them. However, when showing only the node of the image, one has to show them, + /// as their is no HTML node in which they are displayed. There are many more cases where this + /// variable needs to be obeyed. + /// This variable is set to false again when processing the children in stdChildHandling(), as + /// the children can be completely displayed again. + bool mShowOnlyOneMimePart; + + bool mKeepEncryptions; + bool mIncludeSignatures; + bool mHasPendingAsyncJobs; + bool mAllowAsync; + const AttachmentStrategy * mAttachmentStrategy; + HtmlWriter * mHtmlWriter; + CSSHelper * mCSSHelper; + // DataUrl Icons cache + QString mCollapseIcon; + QString mExpandIcon; + +}; + +} + +#endif // _KMAIL_OBJECTTREEPARSER_H_ + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeparser_p.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeparser_p.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeparser_p.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeparser_p.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,344 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + objecttreeparser_p.cpp + + This file is part of KMail, the KDE mail client. + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Klarälvdalens Datakonsult AB + Authors: Marc Mutz + Copyright (c) 2009 Andras Mantia + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "objecttreeparser_p.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +using namespace Kleo; +using namespace GpgME; +using namespace MessageViewer; + +DecryptVerifyBodyPartMemento::DecryptVerifyBodyPartMemento( DecryptVerifyJob * job, const QByteArray & cipherText ) + : QObject( 0 ), + Interface::BodyPartMemento(), + m_cipherText( cipherText ), + m_job( job ), + m_running( false ) +{ + assert( m_job ); +} + +DecryptVerifyBodyPartMemento::~DecryptVerifyBodyPartMemento() { + if ( m_job ) + m_job->slotCancel(); +} + +bool DecryptVerifyBodyPartMemento::start() { + assert( m_job ); + if ( const Error err = m_job->start( m_cipherText ) ) { + m_dr = DecryptionResult( err ); + return false; + } + connect( m_job, SIGNAL(result(const GpgME::DecryptionResult&,const GpgME::VerificationResult&,const QByteArray&)), + this, SLOT(slotResult(const GpgME::DecryptionResult&,const GpgME::VerificationResult&,const QByteArray&)) ); + m_running = true; + return true; +} + +void DecryptVerifyBodyPartMemento::exec() { + assert( m_job ); + QByteArray plainText; + m_running = true; + const std::pair p = m_job->exec( m_cipherText, plainText ); + saveResult( p.first, p.second, plainText ); + m_job->deleteLater(); // exec'ed jobs don't delete themselves + m_job = 0; +} + +void DecryptVerifyBodyPartMemento::saveResult( const DecryptionResult & dr, + const VerificationResult & vr, + const QByteArray & plainText ) +{ + assert( m_job ); + m_running = false; + m_dr = dr; + m_vr = vr; + m_plainText = plainText; + m_auditLog = m_job->auditLogAsHtml(); + m_auditLogError = m_job->auditLogError(); +} + +void DecryptVerifyBodyPartMemento::slotResult( const DecryptionResult & dr, + const VerificationResult & vr, + const QByteArray & plainText ) +{ + saveResult( dr, vr, plainText ); + m_job = 0; + QTimer::singleShot( 100, this, SLOT(notify()) ); +} + + + + +VerifyDetachedBodyPartMemento::VerifyDetachedBodyPartMemento( VerifyDetachedJob * job, + KeyListJob * klj, + const QByteArray & signature, + const QByteArray & plainText ) + : QObject( 0 ), + Interface::BodyPartMemento(), + m_signature( signature ), + m_plainText( plainText ), + m_job( job ), + m_keylistjob( klj ), + m_running( false ) +{ + assert( m_job ); +} + +VerifyDetachedBodyPartMemento::~VerifyDetachedBodyPartMemento() { + if ( m_job ) + m_job->slotCancel(); + if ( m_keylistjob ) + m_keylistjob->slotCancel(); +} + +bool VerifyDetachedBodyPartMemento::start() { + assert( m_job ); + if ( const Error err = m_job->start( m_signature, m_plainText ) ) { + m_vr = VerificationResult( err ); + return false; + } + connect( m_job, SIGNAL(result(const GpgME::VerificationResult&)), + this, SLOT(slotResult(const GpgME::VerificationResult&)) ); + m_running = true; + return true; +} + +void VerifyDetachedBodyPartMemento::exec() { + assert( m_job ); + m_running = true; + saveResult( m_job->exec( m_signature, m_plainText ) ); + m_job->deleteLater(); // exec'ed jobs don't delete themselves + m_job = 0; + if ( canStartKeyListJob() ) { + std::vector keys; + m_keylistjob->exec( keyListPattern(), /*secretOnly=*/false, keys ); + if ( !keys.empty() ) + m_key = keys.back(); + } + if ( m_keylistjob ) + m_keylistjob->deleteLater(); // exec'ed jobs don't delete themselves + m_keylistjob = 0; + m_running = false; +} + +bool VerifyDetachedBodyPartMemento::canStartKeyListJob() const +{ + if ( !m_keylistjob ) + return false; + const char * const fpr = m_vr.signature( 0 ).fingerprint(); + return fpr && *fpr; +} + +QStringList VerifyDetachedBodyPartMemento::keyListPattern() const +{ + assert( canStartKeyListJob() ); + return QStringList( QString::fromLatin1( m_vr.signature( 0 ).fingerprint() ) ); +} + +void VerifyDetachedBodyPartMemento::saveResult( const VerificationResult & vr ) +{ + assert( m_job ); + m_vr = vr; + m_auditLog = m_job->auditLogAsHtml(); + m_auditLogError = m_job->auditLogError(); +} + +void VerifyDetachedBodyPartMemento::slotResult( const VerificationResult & vr ) +{ + saveResult( vr ); + m_job = 0; + if ( canStartKeyListJob() && startKeyListJob() ) + return; + if ( m_keylistjob ) + m_keylistjob->deleteLater(); + m_keylistjob = 0; + m_running = false; + QTimer::singleShot( 100, this, SLOT(notify()) ); +} + +bool VerifyDetachedBodyPartMemento::startKeyListJob() +{ + assert( canStartKeyListJob() ); + if ( const GpgME::Error err = m_keylistjob->start( keyListPattern() ) ) + return false; + connect( m_keylistjob, SIGNAL(done()), this, SLOT(slotKeyListJobDone()) ); + connect( m_keylistjob, SIGNAL(nextKey(const GpgME::Key&)), + this, SLOT(slotNextKey(const GpgME::Key&)) ); + return true; +} + +void VerifyDetachedBodyPartMemento::slotNextKey( const GpgME::Key & key ) +{ + m_key = key; +} + +void VerifyDetachedBodyPartMemento::slotKeyListJobDone() +{ + m_keylistjob = 0; + m_running = false; + QTimer::singleShot( 100, this, SLOT(notify()) ); +} + +void VerifyDetachedBodyPartMemento::notify() +{ + + emit update(Viewer::Force); +} + +VerifyOpaqueBodyPartMemento::VerifyOpaqueBodyPartMemento( VerifyOpaqueJob * job, + KeyListJob * klj, + const QByteArray & signature ) + : QObject( 0 ), + Interface::BodyPartMemento(), + m_signature( signature ), + m_job( job ), + m_keylistjob( klj ), + m_running( false ) +{ + assert( m_job ); +} + +VerifyOpaqueBodyPartMemento::~VerifyOpaqueBodyPartMemento() { + if ( m_job ) + m_job->slotCancel(); + if ( m_keylistjob ) + m_keylistjob->slotCancel(); +} + +bool VerifyOpaqueBodyPartMemento::start() { + assert( m_job ); + if ( const Error err = m_job->start( m_signature ) ) { + m_vr = VerificationResult( err ); + return false; + } + connect( m_job, SIGNAL(result(const GpgME::VerificationResult&,const QByteArray&)), + this, SLOT(slotResult(const GpgME::VerificationResult&,const QByteArray&)) ); + m_running = true; + return true; +} + +void VerifyOpaqueBodyPartMemento::exec() { + assert( m_job ); + m_running = true; + QByteArray plainText; + saveResult( m_job->exec( m_signature, plainText ), plainText ); + m_job->deleteLater(); // exec'ed jobs don't delete themselves + m_job = 0; + if ( canStartKeyListJob() ) { + std::vector keys; + m_keylistjob->exec( keyListPattern(), /*secretOnly=*/false, keys ); + if ( !keys.empty() ) + m_key = keys.back(); + } + if ( m_keylistjob ) + m_keylistjob->deleteLater(); // exec'ed jobs don't delete themselves + m_keylistjob = 0; + m_running = false; +} + +bool VerifyOpaqueBodyPartMemento::canStartKeyListJob() const +{ + if ( !m_keylistjob ) + return false; + const char * const fpr = m_vr.signature( 0 ).fingerprint(); + return fpr && *fpr; +} + +QStringList VerifyOpaqueBodyPartMemento::keyListPattern() const +{ + assert( canStartKeyListJob() ); + return QStringList( QString::fromLatin1( m_vr.signature( 0 ).fingerprint() ) ); +} + +void VerifyOpaqueBodyPartMemento::saveResult( const VerificationResult & vr, + const QByteArray & plainText ) +{ + assert( m_job ); + m_vr = vr; + m_plainText = plainText; + m_auditLog = m_job->auditLogAsHtml(); + m_auditLogError = m_job->auditLogError(); +} + +void VerifyOpaqueBodyPartMemento::slotResult( const VerificationResult & vr, + const QByteArray & plainText ) +{ + saveResult( vr, plainText ); + m_job = 0; + if ( canStartKeyListJob() && startKeyListJob() ) + return; + if ( m_keylistjob ) + m_keylistjob->deleteLater(); + m_keylistjob = 0; + m_running = false; + QTimer::singleShot( 100, this, SLOT(notify()) ); +} + +bool VerifyOpaqueBodyPartMemento::startKeyListJob() +{ + assert( canStartKeyListJob() ); + if ( const GpgME::Error err = m_keylistjob->start( keyListPattern() ) ) + return false; + connect( m_keylistjob, SIGNAL(done()), this, SLOT(slotKeyListJobDone()) ); + connect( m_keylistjob, SIGNAL(nextKey(const GpgME::Key&)), + this, SLOT(slotNextKey(const GpgME::Key&)) ); + return true; +} + +void VerifyOpaqueBodyPartMemento::slotNextKey( const GpgME::Key & key ) +{ + m_key = key; +} + +void VerifyOpaqueBodyPartMemento::slotKeyListJobDone() +{ + m_keylistjob = 0; + m_running = false; + QTimer::singleShot( 100, this, SLOT(notify()) ); +} + + +#include "objecttreeparser_p.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeparser_p.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeparser_p.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeparser_p.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeparser_p.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,211 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + objecttreeparser_p.h + + This file is part of KMail, the KDE mail client. + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef _MESSAGEVIEWER_OBJECTTREEPARSER_P_H_ +#define _MESSAGEVIEWER_OBJECTTREEPARSER_P_H_ + +#include +#include +#include + +#include +#include +#include + +#include "interfaces/bodypart.h" +#include "viewer.h" + +namespace Kleo { + class DecryptVerifyJob; + class VerifyDetachedJob; + class VerifyOpaqueJob; + class KeyListJob; +} + +class QStringList; + +class DecryptVerifyBodyPartMemento + : public QObject, + public MessageViewer::Interface::BodyPartMemento +{ + Q_OBJECT +public: + DecryptVerifyBodyPartMemento( Kleo::DecryptVerifyJob * job, const QByteArray & cipherText ); + ~DecryptVerifyBodyPartMemento(); + + bool start(); + void exec(); + + bool isRunning() const { return m_running; } + + const QByteArray & plainText() const { return m_plainText; } + const GpgME::DecryptionResult & decryptResult() const { return m_dr; } + const GpgME::VerificationResult & verifyResult() const { return m_vr; } + const QString & auditLogAsHtml() const { return m_auditLog; } + GpgME::Error auditLogError() const { return m_auditLogError; } + +private slots: + void slotResult( const GpgME::DecryptionResult & dr, + const GpgME::VerificationResult & vr, + const QByteArray & plainText ); + void notify() { + emit update(MessageViewer::Viewer::Force); + } + +signals: + void update(MessageViewer::Viewer::UpdateMode); + +private: + void saveResult( const GpgME::DecryptionResult &, + const GpgME::VerificationResult &, + const QByteArray & ); +private: + // input: + const QByteArray m_cipherText; + QPointer m_job; + bool m_running; + // output: + GpgME::DecryptionResult m_dr; + GpgME::VerificationResult m_vr; + QByteArray m_plainText; + QString m_auditLog; + GpgME::Error m_auditLogError; +}; + + +class VerifyDetachedBodyPartMemento + : public QObject, + public MessageViewer::Interface::BodyPartMemento +{ + Q_OBJECT +public: + VerifyDetachedBodyPartMemento( Kleo::VerifyDetachedJob * job, + Kleo::KeyListJob * klj, + const QByteArray & signature, + const QByteArray & plainText ); + ~VerifyDetachedBodyPartMemento(); + + bool start(); + void exec(); + + bool isRunning() const { return m_running; } + + const GpgME::VerificationResult & verifyResult() const { return m_vr; } + const QString & auditLogAsHtml() const { return m_auditLog; } + GpgME::Error auditLogError() const { return m_auditLogError; } + const GpgME::Key & signingKey() const { return m_key; } + +private slots: + void slotResult( const GpgME::VerificationResult & vr ); + void slotKeyListJobDone(); + void slotNextKey( const GpgME::Key & ); + void notify(); + +signals: + void update(MessageViewer::Viewer::UpdateMode); + +private: + void saveResult( const GpgME::VerificationResult & ); + bool canStartKeyListJob() const; + QStringList keyListPattern() const; + bool startKeyListJob(); +private: + // input: + const QByteArray m_signature; + const QByteArray m_plainText; + QPointer m_job; + QPointer m_keylistjob; + bool m_running; + // output: + GpgME::VerificationResult m_vr; + QString m_auditLog; + GpgME::Error m_auditLogError; + GpgME::Key m_key; +}; + + +class VerifyOpaqueBodyPartMemento + : public QObject, + public MessageViewer::Interface::BodyPartMemento +{ + Q_OBJECT +public: + VerifyOpaqueBodyPartMemento( Kleo::VerifyOpaqueJob * job, + Kleo::KeyListJob * klj, + const QByteArray & signature ); + ~VerifyOpaqueBodyPartMemento(); + + bool start(); + void exec(); + + bool isRunning() const { return m_running; } + + const QByteArray & plainText() const { return m_plainText; } + const GpgME::VerificationResult & verifyResult() const { return m_vr; } + const QString & auditLogAsHtml() const { return m_auditLog; } + GpgME::Error auditLogError() const { return m_auditLogError; } + const GpgME::Key & signingKey() const { return m_key; } + +private slots: + void slotResult( const GpgME::VerificationResult & vr, + const QByteArray & plainText ); + void slotKeyListJobDone(); + void slotNextKey( const GpgME::Key & ); + void notify() { + emit update(MessageViewer::Viewer::Force); + } + +signals: + void update(MessageViewer::Viewer::UpdateMode); + +private: + void saveResult( const GpgME::VerificationResult &, + const QByteArray & ); + bool canStartKeyListJob() const; + QStringList keyListPattern() const; + bool startKeyListJob(); +private: + // input: + const QByteArray m_signature; + QPointer m_job; + QPointer m_keylistjob; + bool m_running; + // output: + GpgME::VerificationResult m_vr; + QByteArray m_plainText; + QString m_auditLog; + GpgME::Error m_auditLogError; + GpgME::Key m_key; +}; + + +#endif // _KMAIL_OBJECTTREEPARSER_H_ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreesourceif.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreesourceif.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreesourceif.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreesourceif.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,88 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#ifndef MAILVIEWER_OBJECTTREESOURCE_IF_H +#define MAILVIEWER_OBJECTTREESOURCE_IF_H + +#include "messageviewer_export.h" + +namespace KMime { + class Message; +} + +class QObject; +class QTextCodec; + +namespace MessageViewer { + class HtmlWriter; + class CSSHelper; + class AttachmentStrategy; +} + +namespace MessageViewer { +/** @author Andras Mantia */ + +/** Interface for object tree sources.*/ +class MESSAGEVIEWER_EXPORT ObjectTreeSourceIf { + +public: + ObjectTreeSourceIf() {}; + virtual ~ObjectTreeSourceIf() {}; + + /** Return true if the mail should be parsed as a html mail */ + virtual bool htmlMail() = 0; + + /** Return true if an encrypted mail should be decrypted */ + + virtual bool decryptMessage() = 0; + + /** Return true if external sources should be loaded in a html mail */ + virtual bool htmlLoadExternal() = 0; + + /** Return true to include the signature detailes in the generated html */ + virtual bool showSignatureDetails() = 0; + + /** Enable html mode (html statusbar) */ + virtual void setHtmlMode( bool htmlMode ) = 0; + + virtual int levelQuote() = 0; + + /** The override codec that should be used for the mail */ + virtual const QTextCodec * overrideCodec() = 0; + + virtual QString createMessageHeader( KMime::Message* message) = 0; + + /** Disable drag and drop in the sourceObject */ + virtual void emitNoDrag() = 0; + + /** Return the wanted attachment startegy */ + virtual const AttachmentStrategy * attachmentStrategy() = 0; + + /** Return the html write object */ + virtual HtmlWriter * htmlWriter() = 0; + + /** Return the css helper object */ + virtual CSSHelper* cssHelper() = 0; + + /** The source object behind the interface. */ + virtual QObject *sourceObject() = 0; +}; +} + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeviewersource.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeviewersource.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeviewersource.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeviewersource.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,103 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#include "objecttreeviewersource.h" +#include "viewer_p.h" +#include "htmlstatusbar.h" + +namespace MessageViewer { +MailViewerSource::MailViewerSource( ViewerPrivate *viewer ) : + ObjectTreeSourceIf(), mViewer( viewer ) +{ +} + +MailViewerSource::~MailViewerSource() +{ +} + +bool MailViewerSource::htmlMail() +{ + return mViewer->htmlMail(); +} + +bool MailViewerSource::decryptMessage() +{ + return mViewer->decryptMessage(); +} + +bool MailViewerSource::htmlLoadExternal() +{ + return mViewer->htmlLoadExternal(); +} + +bool MailViewerSource::showSignatureDetails() +{ + return mViewer->mShowSignatureDetails; +} + +void MailViewerSource::setHtmlMode( bool mode ) +{ + if ( mode ) { + mViewer->mColorBar->setHtmlMode(); + } else { + mViewer->mColorBar->setNormalMode(); + } +} + +int MailViewerSource::levelQuote() +{ + return mViewer->mLevelQuote; +} + +const QTextCodec * MailViewerSource::overrideCodec() +{ + return mViewer->overrideCodec(); +} + +QString MailViewerSource::createMessageHeader( KMime::Message* message ) +{ + return mViewer->writeMsgHeader( message ); +} + +void MailViewerSource::emitNoDrag() +{ + mViewer->emitNoDrag(); +} + +QObject *MailViewerSource::sourceObject() +{ + return mViewer; +} + +const AttachmentStrategy * MailViewerSource::attachmentStrategy() +{ + return mViewer->attachmentStrategy(); +} + +HtmlWriter * MailViewerSource::htmlWriter() +{ + return mViewer->htmlWriter(); +} + +CSSHelper* MailViewerSource::cssHelper() +{ + return mViewer->cssHelper(); +} + +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeviewersource.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeviewersource.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/objecttreeviewersource.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/objecttreeviewersource.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,57 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#ifndef MAILVIEWER_VIEWERSOURCE_H +#define MAILVIEWER_VIEWERSOURCE_H + +#include "objecttreesourceif.h" + +class QString; + +namespace MessageViewer { + +class ViewerPrivate; + +/** An ObjectTreeParser source working on a MailViewer object */ +class MailViewerSource : public ObjectTreeSourceIf { + public: + MailViewerSource( ViewerPrivate * viewer); + ~MailViewerSource(); + bool htmlMail(); + bool decryptMessage(); + bool htmlLoadExternal(); + bool showSignatureDetails(); + void setHtmlMode( bool mode ); + int levelQuote(); + const QTextCodec * overrideCodec(); + QString createMessageHeader( KMime::Message* message); + void emitNoDrag(); + const AttachmentStrategy * attachmentStrategy(); + HtmlWriter * htmlWriter(); + CSSHelper* cssHelper(); + QObject *sourceObject(); + + private: + ViewerPrivate *mViewer; +}; + +} + +#endif + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/partmetadata.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/partmetadata.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/partmetadata.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/partmetadata.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,64 @@ +/* -*- c++ -*- + partmetadata.h + + KMail, the KDE mail client. + Copyright (c) 2002-2003 Karl-Heinz Zimmer + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License, + version 2.0, as published by the Free Software Foundation. + 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, US +*/ + + +#ifndef _MESSAGEVIEWER_PARTMETADATA_H_ +#define _MESSAGEVIEWER_PARTMETADATA_H_ + +#include +#include + +#include +#include +#include + +class PartMetaData { +public: + PartMetaData() + : sigSummary( GpgME::Signature::None ), + isSigned( false ), + isGoodSignature( false ), + isEncrypted( false ), + isDecryptable( false ), + inProgress( false ), + technicalProblem( false ), + isEncapsulatedRfc822Message( false ) + { + } + GpgME::Signature::Summary sigSummary; + QString signClass; + QString signer; + QStringList signerMailAddresses; + QByteArray keyId; + Kpgp::Validity keyTrust; + QString status; // to be used for unknown plug-ins + int status_code; // to be used for i18n of OpenPGP and S/MIME CryptPlugs + QString errorText; + QDateTime creationTime; + QString decryptionError; + QString auditLog; + GpgME::Error auditLogError; + bool isSigned : 1; + bool isGoodSignature : 1; + bool isEncrypted : 1; + bool isDecryptable : 1; + bool inProgress : 1; + bool technicalProblem : 1; + bool isEncapsulatedRfc822Message : 1; +}; + + +#endif // _KMAIL_PARTMETADATA_H_ + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/partnodebodypart.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/partnodebodypart.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/partnodebodypart.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/partnodebodypart.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,109 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + partnodebodypart.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Marc Mutz , + Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + + +#include "partnodebodypart.h" +#include "nodehelper.h" + +#include + +#include + +#include + +#include +#include + +using namespace MessageViewer; + +static int serial = 0; + +PartNodeBodyPart::PartNodeBodyPart( KMime::Content *content, const QTextCodec * codec ) + : Interface::BodyPart(), mContent( content ), mCodec( codec ), + mDefaultDisplay( Interface::BodyPart::None ) +{} + +QString PartNodeBodyPart::makeLink( const QString & path ) const { + // FIXME: use a PRNG for the first arg, instead of a serial number + return QString( "x-kmail:/bodypart/%1/%2/%3" ) + .arg( serial++ ).arg( mContent->index().toString() ) + .arg( QString::fromLatin1( KUrl::toPercentEncoding( path, "/" ) ) ); +} + +QString PartNodeBodyPart::asText() const { + if ( !mContent->contentType()->isText() ) + return QString(); + return mCodec->toUnicode( mContent->decodedContent() ); +} + +QByteArray PartNodeBodyPart::asBinary() const { + return mContent->decodedContent(); +} + +QString PartNodeBodyPart::contentTypeParameter( const char * param ) const { + return mContent->contentType()->parameter( param ); +} + +QString PartNodeBodyPart::contentDescription() const { + return mContent->contentDescription()->asUnicodeString(); +} + +QString PartNodeBodyPart::contentDispositionParameter( const char * param ) const { + return mContent->contentDisposition()->parameter( param ); +} + +bool PartNodeBodyPart::hasCompleteBody() const { + kWarning() << "Sorry, not yet implemented."; + return true; +} + +Interface::BodyPartMemento * PartNodeBodyPart::memento() const { + /*TODO(Andras) Volker suggests to use a ContentIndex->Mememnto mapping + Also review if the reader's bodyPartMemento should be returned or the NodeHelper's one + */ + return NodeHelper::instance()->bodyPartMemento( mContent, "__plugin__" ); +} + +void PartNodeBodyPart::setBodyPartMemento( Interface::BodyPartMemento * memento ) { +/*TODO(Andras) Volker suggests to use a ContentIndex->Memento mapping +Also review if the reader's bodyPartMemento should be set or the NodeHelper's one */ + NodeHelper::instance()->setBodyPartMemento( mContent, "__plugin__" , memento ); +} + +Interface::BodyPart::Display PartNodeBodyPart::defaultDisplay() const { + return mDefaultDisplay; +} + +void PartNodeBodyPart::setDefaultDisplay( Interface::BodyPart::Display d ){ + mDefaultDisplay = d; +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/partnodebodypart.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/partnodebodypart.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/partnodebodypart.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/partnodebodypart.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,72 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + partnodebodypart.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Marc Mutz , + Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_PARTNODEBODYPART_H_ +#define __MESSAGEVIEWER_PARTNODEBODYPART_H_ + +#include "interfaces/bodypart.h" + +class QTextCodec; + +namespace KMime { + class Content; +} + +/** + @short an implementation of the BodyPart interface using partNodes +*/ +class PartNodeBodyPart : public MessageViewer::Interface::BodyPart { +public: + explicit PartNodeBodyPart( KMime::Content* content, const QTextCodec * codec=0 ); + + QString makeLink( const QString & path ) const; + QString asText() const; + QByteArray asBinary() const; + QString contentTypeParameter( const char * param ) const; + QString contentDescription() const; + //int contentDisposition() const; + QString contentDispositionParameter( const char * param ) const; + bool hasCompleteBody() const; + + MessageViewer::Interface::BodyPartMemento * memento() const; + void setBodyPartMemento( MessageViewer::Interface::BodyPartMemento * memento ); + BodyPart::Display defaultDisplay() const; + void setDefaultDisplay( BodyPart::Display ); + +private: + KMime::Content *mContent; + const QTextCodec * mCodec; + BodyPart::Display mDefaultDisplay; +}; + +#endif // __MESSAGEVIEWER_PARTNODEBODYPART_H_ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/settings.ui /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/settings.ui --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/settings.ui 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/settings.ui 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,196 @@ + + + /* Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia <andras@kdab.net> + + 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) any later version. + + 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. +*/ + Settings + + + + 0 + 0 + 600 + 435 + + + + Viewer settings + + + + + + Show &HTML status bar + + + + + + + Show spam status &in fancy headers + + + + + + + Replace smileys &by emoticons + + + + + + + Reduce font size for &quoted text + + + + + + + Show &expand/collapse quote marks + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 24 + + + + + + + + Au&tomatic collapse level: + + + kcfg_CollapseQuoteLevelSpin + + + + + + + + + + Qt::Horizontal + + + + 273 + 24 + + + + + + + + + + + 0 + 0 + + + + Fallback character e&ncoding: + + + kcfg_FallbackCharacterEncoding + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + &Override character encoding: + + + kcfg_OverrideCharacterEncoding + + + + + + + + 0 + 0 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + KIntSpinBox + QSpinBox +
knuminput.h
+
+ + KComboBox + QComboBox +
kcombobox.h
+
+
+ + +
diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/spamheaderanalyzer.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/spamheaderanalyzer.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/spamheaderanalyzer.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/spamheaderanalyzer.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,188 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + spamheaderanalyzer.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Patrick Audley + Copyright (c) 2004 Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + + +#include "spamheaderanalyzer.h" + +#include "antispamconfig.h" + +#include +#include + +#include +using namespace MessageViewer; +// static +SpamScores SpamHeaderAnalyzer::getSpamScores( KMime::Message* message ) { + SpamScores scores; + SpamAgents agents = AntiSpamConfig::instance()->uniqueAgents(); + + for ( SpamAgentsIterator it = agents.begin(); it != agents.end(); ++it ) { + float score = -2.0; + + SpamError spamError = errorExtractingAgentString; + + // Skip bogus agents + if ( (*it).scoreType() == SpamAgentNone ) + continue; + + // Do we have the needed score field for this agent? + KMime::Headers::Base *header= message->headerByType( (*it).header() ); + if ( !header ) + continue; + + QString mField = header->asUnicodeString(); + + if ( mField.isEmpty() ) + continue; + + QString scoreString; + bool scoreValid = false; + + if ( (*it).scoreType() != SpamAgentBool ) { + // Can we extract the score? + QRegExp scorePattern = (*it).scorePattern(); + if ( scorePattern.indexIn( mField ) != -1 ) { + scoreString = scorePattern.cap( 1 ); + scoreValid = true; + } + } else + scoreValid = true; + + if ( !scoreValid ) { + spamError = couldNotFindTheScoreField; + kDebug() <<"Score could not be extracted from header '" + << mField << "'"; + } else { + bool floatValid = false; + switch ( (*it).scoreType() ) { + case SpamAgentNone: + spamError = errorExtractingAgentString; + break; + + case SpamAgentBool: + if( (*it).scorePattern().indexIn( mField ) == -1 ) + score = 0.0; + else + score = 100.0; + break; + + case SpamAgentFloat: + score = scoreString.toFloat( &floatValid ); + if ( !floatValid ) { + spamError = couldNotConverScoreToFloat; + kDebug() <<"Score (" << scoreString <<") is no number"; + } + else + score *= 100.0; + break; + + case SpamAgentFloatLarge: + score = scoreString.toFloat( &floatValid ); + if ( !floatValid ) { + spamError = couldNotConverScoreToFloat; + kDebug() <<"Score (" << scoreString <<") is no number"; + } + break; + + case SpamAgentAdjustedFloat: + score = scoreString.toFloat( &floatValid ); + if ( !floatValid ) { + spamError = couldNotConverScoreToFloat; + kDebug() <<"Score (" << scoreString <<") is no number"; + break; + } + + // Find the threshold value. + QString thresholdString; + QRegExp thresholdPattern = (*it).thresholdPattern(); + if ( thresholdPattern.indexIn( mField ) != -1 ) { + thresholdString = thresholdPattern.cap( 1 ); + } + else { + spamError = couldNotFindTheThresholdField; + kDebug() <<"Threshold could not be extracted from header '" + << mField << "'"; + break; + } + float threshold = thresholdString.toFloat( &floatValid ); + if ( !floatValid || ( threshold <= 0.0 ) ) { + spamError = couldNotConvertThresholdToFloatOrThresholdIsNegative; + kDebug() <<"Threshold (" << thresholdString <<") is no" + << "number or is negative"; + break; + } + + // Normalize the score. Anything below 0 means 0%, anything above + // threshold mean 100%. Values between 0 and threshold are mapped + // linearily to 0% - 100%. + if ( score < 0.0 ) + score = 0.0; + else if ( score > threshold ) + score = 100.0; + else + score = score / threshold * 100.0; + break; + } + } + //Find the confidence + float confidence = -2.0; + QString confidenceString = "-2.0"; + bool confidenceValid = false; + // Do we have the needed confidence field for this agent? + QByteArray confidenceHeaderName = (*it).confidenceHeader(); + QString mCField; + if( !confidenceHeaderName.isEmpty() ) + { + KMime::Headers::Base *cHeader = message->headerByType( confidenceHeaderName ); + if ( cHeader ) + { + mCField = cHeader->asUnicodeString(); + if ( ! mCField.isEmpty() ) { + // Can we extract the confidence? + QRegExp cScorePattern = (*it).confidencePattern(); + if ( cScorePattern.indexIn( mCField ) != -1 ) { + confidenceString = cScorePattern.cap( 1 ); + } + confidence = confidenceString.toFloat( &confidenceValid ); + if( !confidenceValid) { + spamError = couldNotConvertConfidenceToFloat; + kDebug() <<"Unable to convert confidence to float:" << confidenceString; + } + } + } + } + scores.append( SpamScore( (*it).name(), spamError, score, confidence*100, mField, mCField ) ); + } + + return scores; +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/spamheaderanalyzer.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/spamheaderanalyzer.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/spamheaderanalyzer.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/spamheaderanalyzer.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,111 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + spamheaderanalyzer.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Patrick Audley + Copyright (c) 2004 Ingo Kloecker + + KMail 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) any later version. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_SPAMHEADERANALYZER_H__ +#define __MESSAGEVIEWER_SPAMHEADERANALYZER_H__ + +#include +#include + +namespace KMime { + class Message; +} + +typedef enum { + noError, + uninitializedStructUsed, + errorExtractingAgentString, + couldNotConverScoreToFloat, + couldNotConvertThresholdToFloatOrThresholdIsNegative, + couldNotFindTheScoreField, + couldNotFindTheThresholdField, + couldNotConvertConfidenceToFloat +} SpamError; + +/** + @short A simple tupel of error, agent, score, confidence and header. + + The score returned is positive if no error has occurred. + error values indicate the following errors: + noError Spam Headers succesfully parsed + uninitializedStructUsed Unintialized struct used + errorExtractingAgentString Error extracing agent string + couldNotConverScoreToFloat Couldn't convert score to float + couldNotConvertThresholdToFloatOrThresholdIsNegative Couldn't convert threshold to float or threshold is negative + couldNotFindTheScoreField Couldn't find the score field + couldNotFindTheThresholdField Couldn't find the threshold field + couldNotConvertConfidenceToFloat Couldn't convert confidence to float +*/ +class SpamScore { +public: + + SpamScore() : mScore( -2.0 ), mConfidence( -2.0 ) {} + SpamScore( const QString & agent, SpamError error, float score, float confidence, + const QString & header, const QString & cheader ) + : mAgent( agent ), mError( error ), mScore( score ), mConfidence( confidence ), + mHeader( header ), mConfidenceHeader( cheader ) {} + QString agent() const { return mAgent; } + float score() const { return mScore; } + float confidence() const { return mConfidence; } + SpamError error() const { return mError; } + QString spamHeader() const { return mHeader; } + QString confidenceHeader() const { return mConfidenceHeader; } + +private: + QString mAgent; + SpamError mError; + float mScore; + float mConfidence; + QString mHeader; + QString mConfidenceHeader; +}; +typedef QList SpamScores; +typedef QList::Iterator SpamScoresIterator; + + +/** + @short Flyweight for analysing spam headers. + @author Patrick Audley + */ +class SpamHeaderAnalyzer { +public: + /** + @short Extract scores from known anti-spam headers + @param message A KMime::Message to examine + @return A list of detected scores. See SpamScore + */ + static SpamScores getSpamScores( KMime::Message *message ); +}; + + +#endif // __SPAMHEADERANALYZER_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/stl_util.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/stl_util.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/stl_util.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/stl_util.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,47 @@ +/* -*- c++ -*- + stl_util.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2004 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KDEPIM__MESSAGEVIEWER__STL_UTIL_H__ +#define __KDEPIM__MESSAGEVIEWER__STL_UTIL_H__ + +template +struct DeleteAndSetToZero { + void operator()( const T * & t ) { delete t; t = 0; } +}; + +template +static inline void deleteAll( T & c ) { + for ( typename T::iterator it = c.begin() ; it != c.end() ; ++it ) { + delete *it ; *it = 0; + } +} + +#endif // __KDEPIM__MESSAGEVIEWER__STL_UTIL_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/stringutil.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/stringutil.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/stringutil.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/stringutil.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,1033 @@ +/* Copyright 2009 Thomas McGuire + + 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 "stringutil.h" +#include "global.h" + +#ifndef KMAIL_UNITTESTS + +#include "kmaddrbook.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#endif +#include + +#ifndef KMAIL_UNITTESTS + +using namespace KMime; +using namespace KMime::Types; +using namespace KMime::HeaderParsing; + +#endif + + +namespace StringUtil +{ + +static void removeTrailingSpace( QString &line ) +{ + int i = line.length()-1; + while( (i >= 0) && ((line[i] == ' ') || (line[i] == '\t'))) + i--; + line.truncate( i+1); +} + +static QString splitLine( QString &line) +{ + removeTrailingSpace( line ); + int i = 0; + int j = -1; + int l = line.length(); + + // TODO: Replace tabs with spaces first. + + while(i < l) + { + QChar c = line[i]; + if ((c == '>') || (c == ':') || (c == '|')) + j = i+1; + else if ((c != ' ') && (c != '\t')) + break; + i++; + } + + if ( j <= 0 ) + { + return ""; + } + if ( i == l ) + { + QString result = line.left(j); + line.clear(); + return result; + } + + QString result = line.left(j); + line = line.mid(j); + return result; +} + + +static QString flowText(QString &text, const QString& indent, int maxLength) +{ + maxLength--; + if (text.isEmpty()) + { + return indent+"\n"; + } + QString result; + while (1) + { + int i; + if ((int) text.length() > maxLength) + { + i = maxLength; + while( (i >= 0) && (text[i] != ' ')) + i--; + if (i <= 0) + { + // Couldn't break before maxLength. + i = maxLength; +// while( (i < (int) text.length()) && (text[i] != ' ')) +// i++; + } + } + else + { + i = text.length(); + } + + QString line = text.left(i); + if (i < (int) text.length()) + text = text.mid(i); + else + text.clear(); + + result += indent + line + '\n'; + + if (text.isEmpty()) + return result; + } +} + +static bool flushPart(QString &msg, QStringList &part, + const QString &indent, int maxLength) +{ + maxLength -= indent.length(); + if (maxLength < 20) maxLength = 20; + + // Remove empty lines at end of quote + while ((part.begin() != part.end()) && part.last().isEmpty()) + { + part.removeLast(); + } + + QString text; + for(QStringList::Iterator it2 = part.begin(); + it2 != part.end(); + ++it2) + { + QString line = (*it2); + + if (line.isEmpty()) + { + if (!text.isEmpty()) + msg += flowText(text, indent, maxLength); + msg += indent + '\n'; + } + else + { + if (text.isEmpty()) + text = line; + else + text += ' '+line.trimmed(); + + if (((int) text.length() < maxLength) || ((int) line.length() < (maxLength-10))) + msg += flowText(text, indent, maxLength); + } + } + if (!text.isEmpty()) + msg += flowText(text, indent, maxLength); + + bool appendEmptyLine = true; + if (!part.count()) + appendEmptyLine = false; + + part.clear(); + return appendEmptyLine; +} + +QString stripSignature ( const QString & msg, bool clearSigned ) +{ + // Following RFC 3676, only > before -- + // I prefer to not delete a SB instead of delete good mail content. + const QRegExp sbDelimiterSearch = clearSigned ? + QRegExp( "(^|\n)[> ]*--\\s?\n" ) : QRegExp( "(^|\n)[> ]*-- \n" ); + // The regular expression to look for prefix change + const QRegExp commonReplySearch = QRegExp( "^[ ]*>" ); + + QString res = msg; + int posDeletingStart = 1; // to start looking at 0 + + // While there are SB delimiters (start looking just before the deleted SB) + while ( ( posDeletingStart = res.indexOf( sbDelimiterSearch , posDeletingStart -1 ) ) >= 0 ) + { + QString prefix; // the current prefix + QString line; // the line to check if is part of the SB + int posNewLine = -1; + int posSignatureBlock = -1; + // Look for the SB beginning + posSignatureBlock = res.indexOf( '-', posDeletingStart ); + // The prefix before "-- "$ + if ( res[posDeletingStart] == '\n' ) ++posDeletingStart; + prefix = res.mid( posDeletingStart, posSignatureBlock - posDeletingStart ); + posNewLine = res.indexOf( '\n', posSignatureBlock ) + 1; + + // now go to the end of the SB + while ( posNewLine < res.size() && posNewLine > 0 ) + { + // handle the undefined case for mid ( x , -n ) where n>1 + int nextPosNewLine = res.indexOf( '\n', posNewLine ); + if ( nextPosNewLine < 0 ) nextPosNewLine = posNewLine - 1; + line = res.mid( posNewLine, nextPosNewLine - posNewLine ); + + // check when the SB ends: + // * does not starts with prefix or + // * starts with prefix+(any substring of prefix) + if ( ( prefix.isEmpty() && line.indexOf( commonReplySearch ) < 0 ) || + ( !prefix.isEmpty() && line.startsWith( prefix ) && + line.mid( prefix.size() ).indexOf( commonReplySearch ) < 0 ) ) + { + posNewLine = res.indexOf( '\n', posNewLine ) + 1; + } + else + break; // end of the SB + } + // remove the SB or truncate when is the last SB + if ( posNewLine > 0 ) + res.remove( posDeletingStart, posNewLine - posDeletingStart ); + else + res.truncate( posDeletingStart ); + } + return res; +} + +#ifndef KMAIL_UNITTESTS + +AddressList splitAddrField( const QByteArray & str ) +{ + AddressList result; + const char * scursor = str.begin(); + if ( !scursor ) + return AddressList(); + const char * const send = str.begin() + str.length(); + if ( !parseAddressList( scursor, send, result ) ) + kDebug() << "Error in address splitting: parseAddressList returned false!"; + return result; +} + +QString generateMessageId( const QString& addr ) +{ + QDateTime datetime = QDateTime::currentDateTime(); + QString msgIdStr; + + msgIdStr = '<' + datetime.toString( "yyyyMMddhhmm.sszzz" ); + + QString msgIdSuffix; + KConfigGroup general( Global::instance()->config(), "General" ); + + if( general.readEntry( "useCustomMessageIdSuffix", false ) ) + msgIdSuffix = general.readEntry( "myMessageIdSuffix" ); + + if( !msgIdSuffix.isEmpty() ) + msgIdStr += '@' + msgIdSuffix; + else + msgIdStr += '.' + KPIMUtils::toIdn( addr ); + + msgIdStr += '>'; + + return msgIdStr; +} +#endif + +QByteArray html2source( const QByteArray & src ) +{ + QByteArray result( 1 + 6*src.length(), '\0' ); // maximal possible length + + QByteArray::ConstIterator s = src.begin(); + QByteArray::Iterator d = result.begin(); + while ( *s ) { + switch ( *s ) { + case '<': { + *d++ = '&'; + *d++ = 'l'; + *d++ = 't'; + *d++ = ';'; + ++s; + } + break; + case '\r': { + ++s; + } + break; + case '\n': { + *d++ = '<'; + *d++ = 'b'; + *d++ = 'r'; + *d++ = '>'; + ++s; + } + break; + case '>': { + *d++ = '&'; + *d++ = 'g'; + *d++ = 't'; + *d++ = ';'; + ++s; + } + break; + case '&': { + *d++ = '&'; + *d++ = 'a'; + *d++ = 'm'; + *d++ = 'p'; + *d++ = ';'; + ++s; + } + break; + case '"': { + *d++ = '&'; + *d++ = 'q'; + *d++ = 'u'; + *d++ = 'o'; + *d++ = 't'; + *d++ = ';'; + ++s; + } + break; + case '\'': { + *d++ = '&'; + *d++ = 'a'; + *d++ = 'p'; + *d++ = 's'; + *d++ = ';'; + ++s; + } + break; + default: + *d++ = *s++; + } + } + result.truncate( d - result.begin() ); + return result; +} + +#ifndef KMAIL_UNITTESTS +QString encodeMailtoUrl( const QString& str ) +{ + QString result = QString::fromLatin1( KMime::encodeRFC2047String( str, "utf-8" ) ); + + result = KUrl::toPercentEncoding( result ); + return result; +} + +QString decodeMailtoUrl( const QString& url ) +{ + QString result; + result = KUrl::fromPercentEncoding( url.toLatin1() ); + result = KMime::decodeRFC2047String( result.toLatin1() ); + + return result; +} +#endif + +QByteArray stripEmailAddr( const QByteArray& aStr ) +{ + //kDebug() << "(" << aStr <<" )"; + + if ( aStr.isEmpty() ) + return QByteArray(); + + QByteArray result; + + // The following is a primitive parser for a mailbox-list (cf. RFC 2822). + // The purpose is to extract a displayable string from the mailboxes. + // Comments in the addr-spec are not handled. No error checking is done. + + QByteArray name; + QByteArray comment; + QByteArray angleAddress; + enum { TopLevel, InComment, InAngleAddress } context = TopLevel; + bool inQuotedString = false; + int commentLevel = 0; + + for ( const char* p = aStr.data(); *p; ++p ) { + switch ( context ) { + case TopLevel : { + switch ( *p ) { + case '"' : inQuotedString = !inQuotedString; + break; + case '(' : if ( !inQuotedString ) { + context = InComment; + commentLevel = 1; + } + else + name += *p; + break; + case '<' : if ( !inQuotedString ) { + context = InAngleAddress; + } + else + name += *p; + break; + case '\\' : // quoted character + ++p; // skip the '\' + if ( *p ) + name += *p; + break; + case ',' : if ( !inQuotedString ) { + // next email address + if ( !result.isEmpty() ) + result += ", "; + name = name.trimmed(); + comment = comment.trimmed(); + angleAddress = angleAddress.trimmed(); + /* + kDebug() <<"Name : \"" << name + << "\""; + kDebug() <<"Comment : \"" << comment + << "\""; + kDebug() <<"Address : \"" << angleAddress + << "\""; + */ + if ( angleAddress.isEmpty() && !comment.isEmpty() ) { + // handle Outlook-style addresses like + // john.doe@invalid (John Doe) + result += comment; + } + else if ( !name.isEmpty() ) { + result += name; + } + else if ( !comment.isEmpty() ) { + result += comment; + } + else if ( !angleAddress.isEmpty() ) { + result += angleAddress; + } + name = QByteArray(); + comment = QByteArray(); + angleAddress = QByteArray(); + } + else + name += *p; + break; + default : name += *p; + } + break; + } + case InComment : { + switch ( *p ) { + case '(' : ++commentLevel; + comment += *p; + break; + case ')' : --commentLevel; + if ( commentLevel == 0 ) { + context = TopLevel; + comment += ' '; // separate the text of several comments + } + else + comment += *p; + break; + case '\\' : // quoted character + ++p; // skip the '\' + if ( *p ) + comment += *p; + break; + default : comment += *p; + } + break; + } + case InAngleAddress : { + switch ( *p ) { + case '"' : inQuotedString = !inQuotedString; + angleAddress += *p; + break; + case '>' : if ( !inQuotedString ) { + context = TopLevel; + } + else + angleAddress += *p; + break; + case '\\' : // quoted character + ++p; // skip the '\' + if ( *p ) + angleAddress += *p; + break; + default : angleAddress += *p; + } + break; + } + } // switch ( context ) + } + if ( !result.isEmpty() ) + result += ", "; + name = name.trimmed(); + comment = comment.trimmed(); + angleAddress = angleAddress.trimmed(); + /* + kDebug() <<"Name : \"" << name <<"\""; + kDebug() <<"Comment : \"" << comment <<"\""; + kDebug() <<"Address : \"" << angleAddress <<"\""; + */ + if ( angleAddress.isEmpty() && !comment.isEmpty() ) { + // handle Outlook-style addresses like + // john.doe@invalid (John Doe) + result += comment; + } + else if ( !name.isEmpty() ) { + result += name; + } + else if ( !comment.isEmpty() ) { + result += comment; + } + else if ( !angleAddress.isEmpty() ) { + result += angleAddress; + } + + //kDebug() << "Returns \"" << result << "\""; + return result; +} + +QString stripEmailAddr( const QString& aStr ) +{ + //kDebug() << "(" << aStr << ")"; + + if ( aStr.isEmpty() ) + return QString(); + + QString result; + + // The following is a primitive parser for a mailbox-list (cf. RFC 2822). + // The purpose is to extract a displayable string from the mailboxes. + // Comments in the addr-spec are not handled. No error checking is done. + + QString name; + QString comment; + QString angleAddress; + enum { TopLevel, InComment, InAngleAddress } context = TopLevel; + bool inQuotedString = false; + int commentLevel = 0; + + QChar ch; + int strLength(aStr.length()); + for ( int index = 0; index < strLength; ++index ) { + ch = aStr[index]; + switch ( context ) { + case TopLevel : { + switch ( ch.toLatin1() ) { + case '"' : inQuotedString = !inQuotedString; + break; + case '(' : if ( !inQuotedString ) { + context = InComment; + commentLevel = 1; + } + else + name += ch; + break; + case '<' : if ( !inQuotedString ) { + context = InAngleAddress; + } + else + name += ch; + break; + case '\\' : // quoted character + ++index; // skip the '\' + if ( index < aStr.length() ) + name += aStr[index]; + break; + case ',' : if ( !inQuotedString ) { + // next email address + if ( !result.isEmpty() ) + result += ", "; + name = name.trimmed(); + comment = comment.trimmed(); + angleAddress = angleAddress.trimmed(); + /* + kDebug() <<"Name : \"" << name + << "\""; + kDebug() <<"Comment : \"" << comment + << "\""; + kDebug() <<"Address : \"" << angleAddress + << "\""; + */ + if ( angleAddress.isEmpty() && !comment.isEmpty() ) { + // handle Outlook-style addresses like + // john.doe@invalid (John Doe) + result += comment; + } + else if ( !name.isEmpty() ) { + result += name; + } + else if ( !comment.isEmpty() ) { + result += comment; + } + else if ( !angleAddress.isEmpty() ) { + result += angleAddress; + } + name.clear(); + comment.clear(); + angleAddress.clear(); + } + else + name += ch; + break; + default : name += ch; + } + break; + } + case InComment : { + switch ( ch.toLatin1() ) { + case '(' : ++commentLevel; + comment += ch; + break; + case ')' : --commentLevel; + if ( commentLevel == 0 ) { + context = TopLevel; + comment += ' '; // separate the text of several comments + } + else + comment += ch; + break; + case '\\' : // quoted character + ++index; // skip the '\' + if ( index < aStr.length() ) + comment += aStr[index]; + break; + default : comment += ch; + } + break; + } + case InAngleAddress : { + switch ( ch.toLatin1() ) { + case '"' : inQuotedString = !inQuotedString; + angleAddress += ch; + break; + case '>' : if ( !inQuotedString ) { + context = TopLevel; + } + else + angleAddress += ch; + break; + case '\\' : // quoted character + ++index; // skip the '\' + if ( index < aStr.length() ) + angleAddress += aStr[index]; + break; + default : angleAddress += ch; + } + break; + } + } // switch ( context ) + } + if ( !result.isEmpty() ) + result += ", "; + name = name.trimmed(); + comment = comment.trimmed(); + angleAddress = angleAddress.trimmed(); + /* + kDebug() <<"Name : \"" << name <<"\""; + kDebug() <<"Comment : \"" << comment <<"\""; + kDebug() <<"Address : \"" << angleAddress <<"\""; + */ + if ( angleAddress.isEmpty() && !comment.isEmpty() ) { + // handle Outlook-style addresses like + // john.doe@invalid (John Doe) + result += comment; + } + else if ( !name.isEmpty() ) { + result += name; + } + else if ( !comment.isEmpty() ) { + result += comment; + } + else if ( !angleAddress.isEmpty() ) { + result += angleAddress; + } + + //kDebug() << "Returns \"" << result << "\""; + return result; +} + +QString quoteHtmlChars( const QString& str, bool removeLineBreaks ) +{ + QString result; + + unsigned int strLength(str.length()); + result.reserve( 6*strLength ); // maximal possible length + for( unsigned int i = 0; i < strLength; ++i ) { + switch ( str[i].toLatin1() ) { + case '<': + result += "<"; + break; + case '>': + result += ">"; + break; + case '&': + result += "&"; + break; + case '"': + result += """; + break; + case '\n': + if ( !removeLineBreaks ) + result += "
"; + break; + case '\r': + // ignore CR + break; + default: + result += str[i]; + } + } + + result.squeeze(); + return result; +} + +#ifndef KMAIL_UNITTESTS +QString emailAddrAsAnchor( const QString& aEmail, bool stripped, const QString& cssStyle, + bool aLink ) +{ + if( aEmail.isEmpty() ) + return aEmail; + + const QStringList addressList = KPIMUtils::splitAddressList( aEmail ); + + QString result; + + for( QStringList::ConstIterator it = addressList.constBegin(); + ( it != addressList.constEnd() ); + ++it ) { + if( !(*it).isEmpty() ) { + QString address = *it; + if( aLink ) { + result += ""; + } + if( stripped ) + address = stripEmailAddr( address ); + result += quoteHtmlChars( address, true ); + if( aLink ) { + result += ", "; + } + } + } + // cut of the trailing ", " + if( aLink ) { + result.truncate( result.length() - 2 ); + } + + //kDebug() << "('" << aEmail << "') returns:\n-->" << result << "<--"; + return result; +} + +QStringList stripAddressFromAddressList( const QString& address, + const QStringList& list ) +{ + QStringList addresses( list ); + QString addrSpec( KPIMUtils::extractEmailAddress( address ) ); + for ( QStringList::Iterator it = addresses.begin(); + it != addresses.end(); ) { + if ( kasciistricmp( addrSpec.toUtf8().data(), + KPIMUtils::extractEmailAddress( *it ).toUtf8().data() ) == 0 ) { + kDebug() << "Removing" << *it <<" from the address list"; + it = addresses.erase( it ); + } + else + ++it; + } + return addresses; +} + +QStringList stripMyAddressesFromAddressList( const QStringList& list ) +{ + QStringList addresses = list; + for( QStringList::Iterator it = addresses.begin(); + it != addresses.end(); ) { + kDebug() << "Check whether" << *it <<"is one of my addresses"; + /*FIXME(Andras) port to akonadi + if( kmkernel->identityManager()->thatIsMe( KPIMUtils::extractEmailAddress( *it ) ) ) { + kDebug() << "Removing" << *it <<"from the address list"; + it = addresses.erase( it ); + } + else + */ + ++it; + } + return addresses; +} + +bool addressIsInAddressList( const QString& address, + const QStringList& addresses ) +{ + QString addrSpec = KPIMUtils::extractEmailAddress( address ); + for( QStringList::ConstIterator it = addresses.begin(); + it != addresses.end(); ++it ) { + if ( kasciistricmp( addrSpec.toUtf8().data(), + KPIMUtils::extractEmailAddress( *it ).toUtf8().data() ) == 0 ) + return true; + } + return false; +} + +QString expandAliases( const QString& recipients, QStringList &distributionListEmpty ) +{ + if ( recipients.isEmpty() ) + return QString(); + + QStringList recipientList = KPIMUtils::splitAddressList( recipients ); + QString expandedRecipients; + for ( QStringList::Iterator it = recipientList.begin(); + it != recipientList.end(); ++it ) { + if ( !expandedRecipients.isEmpty() ) + expandedRecipients += ", "; + QString receiver = (*it).trimmed(); + + // try to expand distribution list + bool distributionListIsEmpty = false; + QString expandedList = KPIM::KAddrBookExternal::expandDistributionList( receiver, distributionListIsEmpty ); + if ( distributionListIsEmpty ) { + expandedRecipients += receiver; + distributionListEmpty << receiver; + continue; + } + + if ( !expandedList.isEmpty()) { + expandedRecipients += expandedList; + continue; + } + + // try to expand nick name + QString expandedNickName = KabcBridge::expandNickName( receiver ); + if ( !expandedNickName.isEmpty() ) { + expandedRecipients += expandedNickName; + continue; + } + + // check whether the address is missing the domain part + QByteArray displayName, addrSpec, comment; + KPIMUtils::splitAddress( receiver.toLatin1(), displayName, addrSpec, comment ); + if ( !addrSpec.contains('@') ) { + KConfigGroup general( Global::instance()->config(), "General" ); + QString defaultdomain = general.readEntry( "Default domain" ); + if ( !defaultdomain.isEmpty() ) { + expandedRecipients += KPIMUtils::normalizedAddress( displayName, addrSpec + '@' + defaultdomain, comment ); + } + else { + expandedRecipients += guessEmailAddressFromLoginName( addrSpec ); + } + } + else + expandedRecipients += receiver; + } + + return expandedRecipients; +} + +QString guessEmailAddressFromLoginName( const QString& loginName ) +{ + if ( loginName.isEmpty() ) + return QString(); + + QString address = loginName; + address += '@'; + address += QHostInfo::localHostName(); + + // try to determine the real name + const KUser user( loginName ); + if ( user.isValid() ) { + QString fullName = user.property( KUser::FullName ).toString(); + if ( fullName.contains( QRegExp( "[^ 0-9A-Za-z\\x0080-\\xFFFF]" ) ) ) + address = '"' + fullName.replace( '\\', "\\" ).replace( '"', "\\" ) + + "\" <" + address + '>'; + else + address = fullName + " <" + address + '>'; + } + + return address; +} +#endif + +QString smartQuote( const QString & msg, int maxLineLength ) +{ + QStringList part; + QString oldIndent; + bool firstPart = true; + + const QStringList lines = msg.split('\n'); + + QString result; + for(QStringList::const_iterator it = lines.begin(); + it != lines.end(); + ++it) + { + QString line = *it; + + const QString indent = splitLine( line ); + + if ( line.isEmpty()) + { + if (!firstPart) + part.append(QString()); + continue; + }; + + if (firstPart) + { + oldIndent = indent; + firstPart = false; + } + + if (oldIndent != indent) + { + QString fromLine; + // Search if the last non-blank line could be "From" line + if (part.count() && (oldIndent.length() < indent.length())) + { + QStringList::Iterator it2 = part.isEmpty() ? part.end() : --part.end(); + // FIXME: what if all strings are empty? Then we'll decrement part.begin(). + // Shouldn't we also check for .begin()? + while( (it2 != part.end()) && (*it2).isEmpty()) + --it2; + + if ((it2 != part.end()) && ((*it2).endsWith(':'))) + { + fromLine = oldIndent + (*it2) + '\n'; + part.erase(it2); + } + } + if (flushPart( result, part, oldIndent, maxLineLength)) + { + if (oldIndent.length() > indent.length()) + result += indent + '\n'; + else + result += oldIndent + '\n'; + } + if (!fromLine.isEmpty()) + { + result += fromLine; + } + oldIndent = indent; + } + part.append(line); + } + flushPart( result, part, oldIndent, maxLineLength); + return result; +} + +bool isCryptoPart( const QString &type, const QString &subType, const QString &fileName ) +{ + return ( type.toLower() == "application" && + ( subType.toLower() == "pgp-encrypted" || + subType.toLower() == "pgp-signature" || + subType.toLower() == "pkcs7-mime" || + subType.toLower() == "pkcs7-signature" || + subType.toLower() == "x-pkcs7-signature" || + ( subType.toLower() == "octet-stream" && + fileName.toLower() == "msg.asc" ) ) ); +} + +QString formatString( const QString &wildString, const QString &fromAddr ) +{ + QString result; + + if ( wildString.isEmpty() ) { + return wildString; + } + + unsigned int strLength( wildString.length() ); + for ( uint i=0; i' '; j++ ) + ; + unsigned int strLength( str.length() ); + for ( ; j < strLength && str[j] <= ' '; j++ ) + ; + result += str[0]; + if ( str[j] > ' ' ) { + result += str[j]; + } else { + if ( str[1] > ' ' ) { + result += str[1]; + } + } + } + break; + case '_': + result += ' '; + break; + case '%': + result += '%'; + break; + default: + result += '%'; + result += ch; + break; + } + } else { + result += ch; + } + } + return result; +} + +void parseMailtoUrl ( const KUrl& url, QString& to, QString& cc, QString& subject, QString& body ) +{ + to = decodeMailtoUrl( url.path() ); + body = url.queryItem( "body" ); + subject = url.queryItem( "subject" ); + kDebug() << url.pathOrUrl(); + cc = url.queryItem( "cc" ); +} + + +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/stringutil.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/stringutil.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/stringutil.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/stringutil.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,179 @@ +/* Copyright 2009 Thomas McGuire + + 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 _MESSAGEVIEWER_STRINGUTIL_H +#define _MESSAGEVIEWER_STRINGUTIL_H + +#include + +class KUrl; + +//TODO(Andras) this class probably can be shared between the reader and the composer + +namespace KMime +{ + class CharFreq; + namespace Types + { + struct Address; + typedef QList
AddressList; + } +} + +/** + * This namespace contain helper functions for string manipulation + */ +namespace StringUtil +{ + + /** + * Strips the signature blocks from a message text. "-- " is considered as a signature block separator. + @param msg. The message to remove the signature block from. + @param clearSigned. Before a message is cryptographically signed + all trailing whitespace is removed. Therefore the signature + separator loses the trailing space. + */ + QString stripSignature ( const QString & msg, bool clearSigned ); + + /** + * Splits the given address list into separate addresses. + */ + KMime::Types::AddressList splitAddrField( const QByteArray & str ); + + /** + * Generates the Message-Id. It uses either the Message-Id suffix + * defined by the user or the given email address as suffix. The address + * must be given as addr-spec as defined in RFC 2822. + */ + QString generateMessageId( const QString& addr ); + + /** + * Convert '<' into "<" resp. '>' into ">" in order to + * prevent their interpretation by KHTML. + * Does *not* use the Qt replace function but runs a very fast C code + * the same way as lf2crlf() does. + */ + QByteArray html2source( const QByteArray & src ); + + + /** Encodes an email address as mailto URL + */ + QString encodeMailtoUrl( const QString& str ); + + /** Decodes a mailto URL + */ + QString decodeMailtoUrl( const QString& url ); + + /** + * This function generates a displayable string from a list of email + * addresses. + * Input : mailbox-list + * Output: comma separated list of display name resp. comment resp. + * address + */ + QByteArray stripEmailAddr( const QByteArray& emailAddr ); + + /** + * Does the same as the above function. Shouldn't be used. + */ + QString stripEmailAddr( const QString& emailAddr ); + + /** + * Quotes the following characters which have a special meaning in HTML: + * '<' '>' '&' '"'. Additionally '\\n' is converted to "
" if + * @p removeLineBreaks is false. If @p removeLineBreaks is true, then + * '\\n' is removed. Last but not least '\\r' is removed. + */ + QString quoteHtmlChars( const QString& str, + bool removeLineBreaks = false ); + + /** + * Converts the email address(es) to (a) nice HTML mailto: anchor(s). + * If stripped is true then the visible part of the anchor contains + * only the name part and not the given emailAddr. + */ + QString emailAddrAsAnchor( const QString& emailAddr, + bool stripped = true, const QString& cssStyle = QString(), + bool link = true ); + + /** + * Strips an address from an address list. This is for example used + * when replying to all. + */ + QStringList stripAddressFromAddressList( const QString& address, + const QStringList& addresses ); + + /** + * Strips all the user's addresses from an address list. This is used + * when replying. + */ + QStringList stripMyAddressesFromAddressList( const QStringList& list ); + + /** + * Returns true if the given address is contained in the given address list. + */ + bool addressIsInAddressList( const QString& address, + const QStringList& addresses ); + + /** + * Expands aliases (distribution lists and nick names) and appends a + * domain part to all email addresses which are missing the domain part. + */ + QString expandAliases( const QString& recipients,QStringList &distributionListIsEmpty ); + + /** + * Uses the hostname as domain part and tries to determine the real name + * from the entries in the password file. + */ + QString guessEmailAddressFromLoginName( const QString& userName ); + + /** + * Given argument msg add quoting characters and relayout for max width maxLength + * @param msg the string which it to be quoted + * @param maxLineLength reformat text to be this amount of columns at maximum, adding + * linefeeds at word boundaries to make it fit. + */ + QString smartQuote( const QString &msg, int maxLineLength ); + + /** + * Convert wildcards into normal string + * @param wildString the string to be converted + * @fromAddr from email address to convert to displayable string + */ + QString formatString( const QString &wildString, const QString &fromAddr = QString() ); + + /** + * Parses a mailto: url and extracts the information about to, cc, subject and body out into + * the QStrings given as argument. + */ + void parseMailtoUrl( const KUrl &url, QString &to, QString &cc, QString &subject, QString &body ); + + /** + * Determines if the MIME part with the specified type and subtype is a crypto part. + * For example, this function returns true for type "application" and subtype "pgp-encrypted". + * The filename is needed if the part is named "msg.asc", in which case it is also a crypto part. + * + * This function is useful for finding out if the part should be handled as attachment or not. + * + * All strings are handled case-insensitive. + */ + bool isCryptoPart( const QString &type, const QString &subType, const QString &fileName ); +} + + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/teehtmlwriter.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/teehtmlwriter.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/teehtmlwriter.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/teehtmlwriter.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,95 @@ +/* -*- c++ -*- + teehtmlwriter.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + + +#include "teehtmlwriter.h" + +#include + + + +namespace MessageViewer { + + TeeHtmlWriter::TeeHtmlWriter( HtmlWriter * writer1, HtmlWriter * writer2 ) + : HtmlWriter() + { + if ( writer1 ) + mWriters.append( writer1 ); + if ( writer2 ) + mWriters.append( writer2 ); + } + + TeeHtmlWriter::~TeeHtmlWriter() { + for ( QList::Iterator it = mWriters.begin(); it != mWriters.end(); ++it ) + delete (*it); + } + + void TeeHtmlWriter::addHtmlWriter( HtmlWriter * writer ) { + if ( writer ) + mWriters.append( writer ); + } + + void TeeHtmlWriter::begin( const QString & css ) { + for ( QList::Iterator it = mWriters.begin(); it != mWriters.end(); ++it ) + (*it)->begin( css ); + } + + void TeeHtmlWriter::end() { + for ( QList::Iterator it = mWriters.begin(); it != mWriters.end(); ++it ) + (*it)->end(); + } + + void TeeHtmlWriter::reset() { + for ( QList::Iterator it = mWriters.begin(); it != mWriters.end(); ++it ) + (*it)->reset(); + } + + void TeeHtmlWriter::write( const QString & str ) { + for ( QList::Iterator it = mWriters.begin(); it != mWriters.end(); ++it ) + (*it)->write( str ); + } + + void TeeHtmlWriter::queue( const QString & str ) { + for ( QList::Iterator it = mWriters.begin(); it != mWriters.end(); ++it ) + (*it)->queue( str ); + } + + void TeeHtmlWriter::flush() { + for ( QList::Iterator it = mWriters.begin(); it != mWriters.end(); ++it ) + (*it)->flush(); + } + + void TeeHtmlWriter::embedPart( const QByteArray & contentId, const QString & url ) { + for ( QList::Iterator it = mWriters.begin(); it != mWriters.end(); ++it ) + (*it)->embedPart( contentId, url ); + } + +} // namespace KMail diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/teehtmlwriter.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/teehtmlwriter.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/teehtmlwriter.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/teehtmlwriter.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,72 @@ +/* -*- c++ -*- + teehtmlwriter.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_TEEHTMLWRITER_H__ +#define __MESSAVEVIEWER_TEEHTMLWRITER_H__ + +#include "interfaces/htmlwriter.h" + +#include + +class QString; + +namespace MessageViewer { + + /** @short A HtmlWriter that dispatches all calls to a list of other HtmlWriters + @author Marc Mutz + **/ + class TeeHtmlWriter : public MessageViewer::HtmlWriter { + public: + explicit TeeHtmlWriter( MessageViewer::HtmlWriter * writer1=0, + MessageViewer::HtmlWriter * writer2=0 ); + virtual ~TeeHtmlWriter(); + + void addHtmlWriter( MessageViewer::HtmlWriter * writer ); + + // + // HtmlWriter Interface + // + void begin( const QString & cssDefs ); + void end(); + void reset(); + void write( const QString & str ); + void queue( const QString & str ); + void flush(); + void embedPart( const QByteArray & contentId, const QString & url ); + + private: + /** We own the HtmlWriters added to us! */ + QList mWriters; + }; + +} // namespace MessageViewer + +#endif // __MESSAGEVIEWER_TEEHTMLWRITER_H__ diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/tests/CMakeLists.txt /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/tests/CMakeLists.txt --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/tests/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/tests/CMakeLists.txt 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,18 @@ +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) + +include_directories( + ${CMAKE_SOURCE_DIR}/messageviewer/ + ${Boost_INCLUDE_DIRS} +) + +########### htmlquotecolorertest ############### +set(htmlquotecolorertest_SRCS htmlquotecolorertest.cpp ../htmlquotecolorer.cpp) +kde4_add_unit_test(htmlquotecolorertest TESTNAME kmail-quotecolorertest ${htmlquotecolorertest_SRCS}) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}") +target_link_libraries(htmlquotecolorertest + ${QT_QTTEST_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${KDE4_KHTML_LIBRARY} + messageviewer +) + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/tests/htmlquotecolorertest.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/tests/htmlquotecolorertest.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/tests/htmlquotecolorertest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/tests/htmlquotecolorertest.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,75 @@ +/* Copyright 2009 Thomas McGuire + + 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 "htmlquotecolorertest.h" + +#include "htmlquotecolorer.h" + +#include "qtest_kde.h" + + +QTEST_KDEMAIN( HTMLQuoteColorerTester, GUI ) + +void HTMLQuoteColorerTester::test_QuoteColor() +{ + QFETCH( QString, originalCode ); + QFETCH( QString, expectedCode ); + + HTMLQuoteColorer colorer; + colorer.setQuoteColor( 0, QColor( "#FF0000" ) ); + colorer.setQuoteColor( 1, QColor( "#00FF00" ) ); + colorer.setQuoteColor( 2, QColor( "#0000FF" ) ); + QCOMPARE( colorer.process( originalCode ), expectedCode ); +} + +void HTMLQuoteColorerTester::test_QuoteColor_data() +{ + QTest::addColumn( "originalCode" ); + QTest::addColumn( "expectedCode" ); + + QTest::newRow( "" ) << "Some unquoted text." + << "Some unquoted text."; + QTest::newRow( "" ) << "Some unquoted >text." + << "Some unquoted >text."; + QTest::newRow( "" ) << "Some unquoted \n>text." + << "Some unquoted \n>text."; + QTest::newRow( "" ) << "Some unquoted >text." + << "Some unquoted >text."; + QTest::newRow( "" ) << ">Some quoted text." + << ">Some quoted text."; + QTest::newRow( "" ) << ">Some quoted text." + << ">Some quoted text."; + QTest::newRow( "" ) << ">Some quoted >text." + << ">Some quoted >text."; + QTest::newRow( "" ) << ">Some quoted text." + << ">Some quoted text."; + QTest::newRow( "" ) << "" + ">>>Level 3 Quote
" + "No Quote
" + ">>Level 2 Quote
" + ">Level 1 Quote
" + "No Quote
" + "" + << "" + ">>>Level 3 Quote
" + "No Quote
" + ">>Level 2 Quote
" + ">Level 1 Quote
" + "No Quote
" + ""; +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/tests/htmlquotecolorertest.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/tests/htmlquotecolorertest.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/tests/htmlquotecolorertest.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/tests/htmlquotecolorertest.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,33 @@ +/* Copyright 2009 Thomas McGuire + + 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 HTMLQUOTECOLORERTEST_H +#define HTMLQUOTECOLORERTEST_H + +#include + +class HTMLQuoteColorerTester : public QObject +{ + Q_OBJECT + + private slots: + void test_QuoteColor_data(); + void test_QuoteColor(); +}; + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/TODO-before-release /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/TODO-before-release --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/TODO-before-release 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/TODO-before-release 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,7 @@ +Remove export from htmlstatusbar.h when we remove old code in kmail +remove export from vcardviewer.h when we remove old code in kmail +remove export from htmlquotecolorer.h when we remove old code in kmail +Look at if mailsourceviewer.h is necessary to be shared. For the moment it used in kmcommand in kmail and perhaps when we convert to akonadi command it will not necessary. +remove export from attachmentdialog.h when we remove old code in kmail +remove export from kleojobexecutor.h when we remove old code in kmail +remove export from khtmlparthtmlwriter.h when we remove old code in kmail diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/urlhandlermanager.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/urlhandlermanager.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/urlhandlermanager.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/urlhandlermanager.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,663 @@ +/* -*- c++ -*- + urlhandlermanager.cpp + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + Copyright (C) 2002-2003, 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + + +#include "urlhandlermanager.h" + +#include "interfaces/urlhandler.h" +#include "interfaces/bodyparturlhandler.h" +#include "partnodebodypart.h" +#include "viewer_p.h" +#include "nodehelper.h" + +#include "stringutil.h" +#include "stl_util.h" +#include + +#include + +#include +#include + +#include + +using std::for_each; +using std::remove; +using std::find; +using namespace MessageViewer; + +URLHandlerManager * URLHandlerManager::self = 0; + +namespace { + class KMailProtocolURLHandler : public URLHandler { + public: + KMailProtocolURLHandler() : URLHandler() {} + ~KMailProtocolURLHandler() {} + + bool handleClick( const KUrl &, ViewerPrivate * ) const; + bool handleContextMenuRequest( const KUrl & url, const QPoint &, ViewerPrivate * ) const { + return url.protocol() == "kmail"; + } + QString statusBarMessage( const KUrl &, ViewerPrivate * ) const; + }; + + class ExpandCollapseQuoteURLManager : public URLHandler { + public: + ExpandCollapseQuoteURLManager() : URLHandler() {} + ~ExpandCollapseQuoteURLManager() {} + + bool handleClick( const KUrl &, ViewerPrivate * ) const; + bool handleContextMenuRequest( const KUrl &, const QPoint &, ViewerPrivate * ) const { + return false; + } + QString statusBarMessage( const KUrl &, ViewerPrivate * ) const; + + }; + + class SMimeURLHandler : public URLHandler { + public: + SMimeURLHandler() : URLHandler() {} + ~SMimeURLHandler() {} + + bool handleClick( const KUrl &, ViewerPrivate * ) const; + bool handleContextMenuRequest( const KUrl &, const QPoint &, ViewerPrivate * ) const { + return false; + } + QString statusBarMessage( const KUrl &, ViewerPrivate * ) const; + }; + + class MailToURLHandler : public URLHandler { + public: + MailToURLHandler() : URLHandler() {} + ~MailToURLHandler() {} + + bool handleClick( const KUrl &, ViewerPrivate * ) const { return false; } + bool handleContextMenuRequest( const KUrl &, const QPoint &, ViewerPrivate * ) const { + return false; + } + QString statusBarMessage( const KUrl &, ViewerPrivate * ) const; + }; + + class HtmlAnchorHandler : public URLHandler { + public: + HtmlAnchorHandler() : URLHandler() {} + ~HtmlAnchorHandler() {} + + bool handleClick( const KUrl &, ViewerPrivate * ) const; + bool handleContextMenuRequest( const KUrl &, const QPoint &, ViewerPrivate * ) const { + return false; + } + QString statusBarMessage( const KUrl &, ViewerPrivate * ) const { return QString(); } + }; + + class AttachmentURLHandler : public URLHandler { + public: + AttachmentURLHandler() : URLHandler() {} + ~AttachmentURLHandler() {} + + bool handleClick( const KUrl &, ViewerPrivate * ) const; + bool handleContextMenuRequest( const KUrl &, const QPoint &, ViewerPrivate * ) const; + QString statusBarMessage( const KUrl &, ViewerPrivate * ) const; + private: + KMime::Content* nodeForUrl( const KUrl &url, ViewerPrivate *w ) const; + bool attachmentIsInHeader( const KUrl &url ) const; + }; + + class ShowAuditLogURLHandler : public URLHandler { + public: + ShowAuditLogURLHandler() : URLHandler() {} + ~ShowAuditLogURLHandler() {} + + bool handleClick( const KUrl &, ViewerPrivate * ) const; + bool handleContextMenuRequest( const KUrl &, const QPoint &, ViewerPrivate * ) const; + QString statusBarMessage( const KUrl &, ViewerPrivate * ) const; + }; + + class FallBackURLHandler : public URLHandler { + public: + FallBackURLHandler() : URLHandler() {} + ~FallBackURLHandler() {} + + bool handleClick( const KUrl &, ViewerPrivate * ) const; + bool handleContextMenuRequest( const KUrl &, const QPoint &, ViewerPrivate * ) const; + QString statusBarMessage( const KUrl & url, ViewerPrivate * ) const { + return url.prettyUrl(); + } + }; + +} // anon namespace + + +// +// +// BodyPartURLHandlerManager +// +// + +class URLHandlerManager::BodyPartURLHandlerManager : public URLHandler { +public: + BodyPartURLHandlerManager() : URLHandler() {} + ~BodyPartURLHandlerManager(); + + bool handleClick( const KUrl &, ViewerPrivate * ) const; + bool handleContextMenuRequest( const KUrl &, const QPoint &, ViewerPrivate * ) const; + QString statusBarMessage( const KUrl &, ViewerPrivate * ) const; + + void registerHandler( const Interface::BodyPartURLHandler * handler ); + void unregisterHandler( const Interface::BodyPartURLHandler * handler ); + +private: + typedef QVector BodyPartHandlerList; + BodyPartHandlerList mHandlers; +}; + +URLHandlerManager::BodyPartURLHandlerManager::~BodyPartURLHandlerManager() { + for_each( mHandlers.begin(), mHandlers.end(), + DeleteAndSetToZero() ); +} + +void URLHandlerManager::BodyPartURLHandlerManager::registerHandler( const Interface::BodyPartURLHandler * handler ) { + if ( !handler ) + return; + unregisterHandler( handler ); // don't produce duplicates + mHandlers.push_back( handler ); +} + +void URLHandlerManager::BodyPartURLHandlerManager::unregisterHandler( const Interface::BodyPartURLHandler * handler ) { + // don't delete them, only remove them from the list! + mHandlers.erase( remove( mHandlers.begin(), mHandlers.end(), handler ), mHandlers.end() ); +} + +static KMime::Content * partNodeFromXKMailUrl( const KUrl & url, ViewerPrivate * w, QString * path ) { + assert( path ); + + if ( !w || url.protocol() != "x-kmail" ) + return 0; + const QString urlPath = url.path(); + + // urlPath format is: /bodypart/// + + kDebug() <<"BodyPartURLHandler: urlPath == \"" << urlPath <<"\""; + if ( !urlPath.startsWith( QLatin1String("/bodypart/") ) ) + return 0; + + const QStringList urlParts = urlPath.mid( 10 ).split( '/' ); + if ( urlParts.size() != 3 ) + return 0; + KMime::ContentIndex index( urlParts[1] ); + *path = KUrl::fromPercentEncoding( urlParts[2].toLatin1() ); + return w->nodeForContentIndex( index ); +} + +bool URLHandlerManager::BodyPartURLHandlerManager::handleClick( const KUrl & url, ViewerPrivate * w ) const { +/*FIXME(Andras) port it + QString path; + partNode * node = partNodeFromXKMailUrl( url, w, &path ); + if ( !node ) + return false; + KMMessage *msg = w->mMessage; + if ( !msg ) return false; + Callback callback( msg, w ); + PartNodeBodyPart part( *node, w->overrideCodec() ); + for ( BodyPartHandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it ) + if ( (*it)->handleClick( &part, path, callback ) ) + return true; + */ + kWarning() <<"FIXME PORT bool URLHandlerManager::BodyPartURLHandlerManager::handleClick( const KUrl & url, MailViewerPrivate * w ) const "; + + return false; +} + +bool URLHandlerManager::BodyPartURLHandlerManager::handleContextMenuRequest( const KUrl & url, const QPoint & p, ViewerPrivate * w ) const { + QString path; + KMime::Content * node = partNodeFromXKMailUrl( url, w, &path ); + if ( !node ) + return false; + + PartNodeBodyPart part( node, w->overrideCodec() ); + for ( BodyPartHandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it ) + if ( (*it)->handleContextMenuRequest( &part, path, p ) ) + return true; + return false; +} + +QString URLHandlerManager::BodyPartURLHandlerManager::statusBarMessage( const KUrl & url, ViewerPrivate * w ) const { + QString path; + KMime::Content * node = partNodeFromXKMailUrl( url, w, &path ); + if ( !node ) + return QString(); + + PartNodeBodyPart part( node, w->overrideCodec() ); + for ( BodyPartHandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it ) { + const QString msg = (*it)->statusBarMessage( &part, path ); + if ( !msg.isEmpty() ) + return msg; + } + return QString(); +} + +// +// +// URLHandlerManager +// +// + +URLHandlerManager::URLHandlerManager() { + registerHandler( new KMailProtocolURLHandler() ); + registerHandler( new ExpandCollapseQuoteURLManager() ); + registerHandler( new SMimeURLHandler() ); + registerHandler( new MailToURLHandler() ); + registerHandler( new HtmlAnchorHandler() ); + registerHandler( new AttachmentURLHandler() ); + registerHandler( mBodyPartURLHandlerManager = new BodyPartURLHandlerManager() ); + registerHandler( new ShowAuditLogURLHandler() ); + registerHandler( new FallBackURLHandler() ); +} + +URLHandlerManager::~URLHandlerManager() { + for_each( mHandlers.begin(), mHandlers.end(), + DeleteAndSetToZero() ); +} + +void URLHandlerManager::registerHandler( const URLHandler * handler ) { + if ( !handler ) + return; + unregisterHandler( handler ); // don't produce duplicates + mHandlers.push_back( handler ); +} + +void URLHandlerManager::unregisterHandler( const URLHandler * handler ) { + // don't delete them, only remove them from the list! + mHandlers.erase( remove( mHandlers.begin(), mHandlers.end(), handler ), mHandlers.end() ); +} + +void URLHandlerManager::registerHandler( const Interface::BodyPartURLHandler * handler ) { + if ( mBodyPartURLHandlerManager ) + mBodyPartURLHandlerManager->registerHandler( handler ); +} + +void URLHandlerManager::unregisterHandler( const Interface::BodyPartURLHandler * handler ) { + if ( mBodyPartURLHandlerManager ) + mBodyPartURLHandlerManager->unregisterHandler( handler ); +} + +bool URLHandlerManager::handleClick( const KUrl & url, ViewerPrivate * w ) const { + for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it ) + if ( (*it)->handleClick( url, w ) ) + return true; + return false; +} + +bool URLHandlerManager::handleContextMenuRequest( const KUrl & url, const QPoint & p, ViewerPrivate * w ) const { + for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it ) + if ( (*it)->handleContextMenuRequest( url, p, w ) ) + return true; + return false; +} + +QString URLHandlerManager::statusBarMessage( const KUrl & url, ViewerPrivate * w ) const { + for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it ) { + const QString msg = (*it)->statusBarMessage( url, w ); + if ( !msg.isEmpty() ) + return msg; + } + return QString(); +} + + +// +// +// URLHandler +// +// + +#include + +#include +#include +#include + +#include + +namespace { + bool KMailProtocolURLHandler::handleClick( const KUrl & url, ViewerPrivate * w ) const { + if ( url.protocol() == "kmail" ) { + if ( !w ) + return false; + + if ( url.path() == "showHTML" ) { + w->setHtmlOverride( !w->htmlOverride() ); + w->update( Viewer::Force ); + return true; + } + + if ( url.path() == "loadExternal" ) { + w->setHtmlLoadExtOverride( !w->htmlLoadExtOverride() ); + w->update( Viewer::Force ); + return true; + } + + if ( url.path() == "decryptMessage" ) { + w->setDecryptMessageOverwrite( true ); + w->update( Viewer::Force ); + return true; + } + + if ( url.path() == "showSignatureDetails" ) { + w->setShowSignatureDetails( true ); + w->update( Viewer::Force ); + return true; + } + + if ( url.path() == "hideSignatureDetails" ) { + w->setShowSignatureDetails( false ); + w->update( Viewer::Force ); + return true; + } + + if ( url.path() == "showAttachmentQuicklist" ) { + w->saveRelativePosition(); + w->setShowAttachmentQuicklist( true ); + w->update( Viewer::Force ); + return true; + } + + if ( url.path() == "hideAttachmentQuicklist" ) { + w->saveRelativePosition(); + w->setShowAttachmentQuicklist( false ); + w->update( Viewer::Force ); + return true; + } + } + return false; + } + + QString KMailProtocolURLHandler::statusBarMessage( const KUrl & url, ViewerPrivate * ) const { + if ( url.protocol() == "kmail" ) + { + if ( url.path() == "showHTML" ) + return i18n("Turn on HTML rendering for this message."); + if ( url.path() == "loadExternal" ) + return i18n("Load external references from the Internet for this message."); + if ( url.path() == "goOnline" ) + return i18n("Work online."); + if ( url.path() == "decryptMessage" ) + return i18n("Decrypt message."); + if ( url.path() == "showSignatureDetails" ) + return i18n("Show signature details."); + if ( url.path() == "hideSignatureDetails" ) + return i18n("Hide signature details."); + if ( url.path() == "showAttachmentQuicklist" ) + return i18n( "Show attachment list." ); + if ( url.path() == "hideAttachmentQuicklist" ) + return i18n( "Hide attachment list." ); + } + return QString() ; + } +} + +namespace { + + bool ExpandCollapseQuoteURLManager::handleClick( + const KUrl & url, ViewerPrivate * w ) const + { + // kmail:levelquote/?num -> the level quote to collapse. + // kmail:levelquote/?-num -> expand all levels quote. + if ( url.protocol() == "kmail" && url.path()=="levelquote" ) + { + QString levelStr= url.query().mid( 1,url.query().length() ); + bool isNumber; + int levelQuote= levelStr.toInt(&isNumber); + if ( isNumber ) + w->slotLevelQuote( levelQuote ); + return true; + } + return false; + } + QString ExpandCollapseQuoteURLManager::statusBarMessage( + const KUrl & url, ViewerPrivate * ) const + { + if ( url.protocol() == "kmail" && url.path() == "levelquote" ) + { + QString query= url.query(); + if ( query.length()>=2 ) { + if ( query[ 1 ] =='-' ) { + return i18n("Expand all quoted text."); + } + else { + return i18n("Collapse quoted text."); + } + } + } + return QString() ; + } + +} + +bool foundSMIMEData( const QString aUrl, + QString& displayName, + QString& libName, + QString& keyId ) +{ + static QString showCertMan("showCertificate#"); + displayName = ""; + libName = ""; + keyId = ""; + int i1 = aUrl.indexOf( showCertMan ); + if( -1 < i1 ) { + i1 += showCertMan.length(); + int i2 = aUrl.indexOf(" ### ", i1); + if( i1 < i2 ) + { + displayName = aUrl.mid( i1, i2-i1 ); + i1 = i2+5; + i2 = aUrl.indexOf(" ### ", i1); + if( i1 < i2 ) + { + libName = aUrl.mid( i1, i2-i1 ); + i2 += 5; + + keyId = aUrl.mid( i2 ); + /* + int len = aUrl.length(); + if( len > i2+1 ) { + keyId = aUrl.mid( i2, 2 ); + i2 += 2; + while( len > i2+1 ) { + keyId += ':'; + keyId += aUrl.mid( i2, 2 ); + i2 += 2; + } + } + */ + } + } + } + return !keyId.isEmpty(); +} + + +namespace { + bool SMimeURLHandler::handleClick( const KUrl & url, ViewerPrivate * w ) const { + if ( !url.hasRef() ) + return false; + QString displayName, libName, keyId; + if ( !foundSMIMEData( url.path() + '#' + + QUrl::fromPercentEncoding( url.ref().toLatin1() ), + displayName, libName, keyId ) ) + return false; + QStringList lst; + lst << "-query" << keyId; + if ( !QProcess::startDetached( "kleopatra",lst) ) + KMessageBox::error( w->mMainWindow, i18n("Could not start certificate manager. " + "Please check your installation."), + i18n("KMail Error") ); + return true; + } + + QString SMimeURLHandler::statusBarMessage( const KUrl & url, ViewerPrivate * ) const { + QString displayName, libName, keyId; + if ( !foundSMIMEData( url.path() + '#' + + QUrl::fromPercentEncoding( url.ref().toLatin1() ), + displayName, libName, keyId ) ) + return QString(); + return i18n("Show certificate 0x%1", keyId ); + } +} + +namespace { + bool HtmlAnchorHandler::handleClick( const KUrl & url, ViewerPrivate * w ) const { + if ( url.hasHost() || url.path() != "/" || !url.hasRef() ) + return false; + if ( w && !w->htmlPart()->gotoAnchor( url.ref() ) ) + static_cast( w->htmlPart()->widget() )->ensureVisible( 0, 0 ); + return true; + } +} + +namespace { + QString MailToURLHandler::statusBarMessage( const KUrl & url, ViewerPrivate * ) const { + if ( url.protocol() != "mailto" ) + return QString(); + return StringUtil::decodeMailtoUrl( url.url() ); + } +} + +namespace { + KMime::Content* AttachmentURLHandler::nodeForUrl( const KUrl &url, ViewerPrivate *w ) const + { + if ( !w || !w->mMessage ) + return 0; + if ( url.protocol() != "attachment" ) + return 0; + + KMime::ContentIndex index( url.path() ); + KMime::Content * node = w->nodeForContentIndex( index ); + return node; + } + + bool AttachmentURLHandler::attachmentIsInHeader( const KUrl &url ) const + { + bool inHeader = false; + const QString place = url.queryItem( "place" ).toLower(); + if ( place != QString::null ) { + inHeader = ( place == "header" ); + } + return inHeader; + } + + bool AttachmentURLHandler::handleClick( const KUrl & url, ViewerPrivate * w ) const + { + KMime::Content *node = nodeForUrl( url, w ); + if ( !node ) + return false; + + const bool inHeader = attachmentIsInHeader( url ); + const bool shouldShowDialog = !NodeHelper::instance()->isNodeDisplayedEmbedded( node ) || !inHeader; + if ( inHeader ) + w->scrollToAttachment( node ); + if ( shouldShowDialog ) + // PENDING(romain_kdab) : replace with toLocalFile() ? + w->openAttachment( node, NodeHelper::instance()->tempFileUrlFromNode( node ).path() ); + + return true; + } + + bool AttachmentURLHandler::handleContextMenuRequest( const KUrl & url, const QPoint & p, ViewerPrivate * w ) const + { + KMime::Content *node = nodeForUrl( url, w ); + if ( !node ) + return false; + + // PENDING(romain_kdab) : replace with toLocalFile() ? + /*FIXME(Andras) port it + w->showAttachmentPopup( node->nodeId(), w->tempFileUrlFromPartNode( node ).path(), p ); + */ + return true; + } + + QString AttachmentURLHandler::statusBarMessage( const KUrl & url, ViewerPrivate * w ) const + { + KMime::Content *node = nodeForUrl( url, w ); + if ( !node ) + return QString(); + QString name = NodeHelper::fileName( node ); + if ( !name.isEmpty() ) + return i18n( "Attachment: %1", name ); + return i18n( "Attachment #%1 (unnamed)", node->index().toString() ); + } +} + +namespace { + static QString extractAuditLog( const KUrl & url ) { + if ( url.protocol() != "kmail" || url.path() != "showAuditLog" ) + return QString(); + assert( !url.queryItem( "log" ).isEmpty() ); + return url.queryItem( "log" ); + } + + bool ShowAuditLogURLHandler::handleClick( const KUrl & url, ViewerPrivate * w ) const { + const QString auditLog = extractAuditLog( url ); + if ( auditLog.isEmpty() ) + return false; + Kleo::MessageBox::auditLog( w->mMainWindow, auditLog ); + return true; + } + + bool ShowAuditLogURLHandler::handleContextMenuRequest( const KUrl & url, const QPoint &, ViewerPrivate * w ) const { + Q_UNUSED( w ); + // disable RMB for my own links: + return !extractAuditLog( url ).isEmpty(); + } + + QString ShowAuditLogURLHandler::statusBarMessage( const KUrl & url, ViewerPrivate * ) const { + if ( extractAuditLog( url ).isEmpty() ) + return QString(); + else + return i18n("Show GnuPG Audit Log for this operation"); + } +} + +namespace { + bool FallBackURLHandler::handleClick( const KUrl & url, ViewerPrivate * w ) const { + if ( w ) + w->emitUrlClicked( url, Qt::LeftButton ); + return true; + } + + bool FallBackURLHandler::handleContextMenuRequest( const KUrl & url, const QPoint & p, ViewerPrivate * w ) const { + if ( w ) + w->emitPopupMenu( url, p ); + return true; + } +} diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/urlhandlermanager.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/urlhandlermanager.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/urlhandlermanager.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/urlhandlermanager.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,91 @@ +/* -*- c++ -*- + urlhandlermanager.h + + This file is part of KMail, the KDE mail client. + Copyright (c) 2003 Marc Mutz + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __MESSAGEVIEWER_URLHANDLERMANAGER_H__ +#define __MESSAGEVIEWER_URLHANDLERMANAGER_H__ + + +#include +class KUrl; + +class QString; +class QPoint; + +namespace MessageViewer { + namespace Interface { + class BodyPartURLHandler; + } + + class ViewerPrivate; + class URLHandler; +} + +namespace MessageViewer { + +/** + * @short Singleton to manage the list of URLHandlers + * @author Marc Mutz + */ +class URLHandlerManager { + static URLHandlerManager * self; + + URLHandlerManager(); +public: + ~URLHandlerManager(); + + static URLHandlerManager * instance() { + if ( !self ) +self = new URLHandlerManager(); + return self; + } + + void registerHandler( const URLHandler * handler ); + void unregisterHandler( const URLHandler * handler ); + + void registerHandler( const MessageViewer::Interface::BodyPartURLHandler * handler ); + void unregisterHandler( const MessageViewer::Interface::BodyPartURLHandler * handler ); + + bool handleClick( const KUrl & url, MessageViewer::ViewerPrivate * w=0 ) const; + bool handleContextMenuRequest( const KUrl & url, const QPoint & p, MessageViewer::ViewerPrivate * w=0 ) const; + QString statusBarMessage( const KUrl & url, MessageViewer::ViewerPrivate* w=0 ) const; + +private: + typedef QVector HandlerList; + HandlerList mHandlers; + class BodyPartURLHandlerManager; + BodyPartURLHandlerManager * mBodyPartURLHandlerManager; +}; +} + +#endif // __MESSAGEVIEWER_URLHANDLERMANAGER_H__ + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/util.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/util.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/util.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/util.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,124 @@ +/******************************************************************************* +** +** Filename : util +** Created on : 03 April, 2005 +** Copyright : (c) 2005 Till Adam +** Email : +** +*******************************************************************************/ + +/******************************************************************************* +** +** 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) any later version. +** +** It 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 +** +** In addition, as a special exception, the copyright holders give +** permission to link the code of this program with any edition of +** the Qt library by Trolltech AS, Norway (or with modified versions +** of Qt that use the same license as Qt), and distribute linked +** combinations including the two. You must obey the GNU General +** Public License in all respects for all of the code used other than +** Qt. If you modify this file, you may extend this exception to +** your version of the file, but you are not obligated to do so. If +** you do not wish to do so, delete this exception statement from +** your version. +** +*******************************************************************************/ + +#include "util.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +bool Util::checkOverwrite( const KUrl &url, QWidget *w ) +{ + if ( KIO::NetAccess::exists( url, KIO::NetAccess::DestinationSide, w ) ) { + if ( KMessageBox::Cancel == KMessageBox::warningContinueCancel( + w, + i18n( "A file named \"%1\" already exists. " + "Are you sure you want to overwrite it?", url.prettyUrl() ), + i18n( "Overwrite File?" ), + KStandardGuiItem::overwrite() ) ) + return false; + } + return true; +} + +#ifdef Q_WS_MACX +#include +#endif + +bool Util::handleUrlOnMac( const KUrl& url ) +{ +#ifdef Q_WS_MACX + QDesktopServices::openUrl( url ); + return true; +#else + Q_UNUSED( url ); + return false; +#endif +} + +QStringList Util::supportedEncodings(bool usAscii) +{ + // cberzan: replaced by KCodecAction in CodecManager + QStringList encodingNames = KGlobal::charsets()->availableEncodingNames(); + QStringList encodings; + QMap mimeNames; + for (QStringList::Iterator it = encodingNames.begin(); + it != encodingNames.end(); ++it) + { + QTextCodec *codec = KGlobal::charsets()->codecForName(*it); +// kDebug() << "name" << *it << "codec" << codec << "name" << (codec ? codec->name() : "NULL"); + QString mimeName = (codec) ? QString(codec->name()).toLower() : (*it); + if (!mimeNames.contains(mimeName) ) + { + encodings.append( KGlobal::charsets()->descriptionForEncoding(*it) ); + mimeNames.insert( mimeName, true ); +// kDebug() << "added" << mimeName; + } + } + encodings.sort(); + if (usAscii) + encodings.prepend(KGlobal::charsets()->descriptionForEncoding("us-ascii") ); + return encodings; +} + +//----------------------------------------------------------------------------- +QString Util::fixEncoding( const QString &encoding ) +{ + QString returnEncoding = encoding; + // According to http://www.iana.org/assignments/character-sets, uppercase is + // preferred in MIME headers + if ( returnEncoding.toUpper().contains( "ISO " ) ) { + returnEncoding = returnEncoding.toUpper(); + returnEncoding.replace( "ISO ", "ISO-" ); + } + return returnEncoding; +} + +//----------------------------------------------------------------------------- +QString Util::encodingForName( const QString &descriptiveName ) +{ + QString encoding = KGlobal::charsets()->encodingForName( descriptiveName ); + return Util::fixEncoding( encoding ); +} + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/util.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/util.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/util.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/util.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,83 @@ +/******************************************************************************* +** +** Filename : util +** Created on : 03 April, 2005 +** Copyright : (c) 2005 Till Adam +** Email : +** +*******************************************************************************/ + +/******************************************************************************* +** +** 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) any later version. +** +** It 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 +** +** In addition, as a special exception, the copyright holders give +** permission to link the code of this program with any edition of +** the Qt library by Trolltech AS, Norway (or with modified versions +** of Qt that use the same license as Qt), and distribute linked +** combinations including the two. You must obey the GNU General +** Public License in all respects for all of the code used other than +** Qt. If you modify this file, you may extend this exception to +** your version of the file, but you are not obligated to do so. If +** you do not wish to do so, delete this exception statement from +** your version. +** +*******************************************************************************/ +#ifndef MAILVIEWERUTIL_H +#define MAILVIEWERUTIL_H + +class KUrl; +class QWidget; +class QStringList; +class QString; + + /** + * The Util namespace contains a collection of helper functions use in + * various places. + */ +namespace Util { + + // return true if we should proceed, false if we should abort + bool checkOverwrite( const KUrl &url, QWidget *w ); + + /** + * Delegates opening a URL to the Max OSX mechanisms for that. + * Returns false if it did nothing (such as on other platforms. + */ + bool handleUrlOnMac( const KUrl& url ); + + /** + * Return a list of the supported encodings + * @param usAscii if true, US-Ascii encoding will be prepended to the list. + */ + QStringList supportedEncodings( bool usAscii ); + + /** + * Fixes an encoding received by a KDE function and returns the proper, + * MIME-compilant encoding name instead. + * @see encodingForName + */ + QString fixEncoding( const QString &encoding ); + + /** + * Drop-in replacement for KCharsets::encodingForName(). The problem with + * the KCharsets function is that it returns "human-readable" encoding names + * like "ISO 8859-15" instead of valid encoding names like "ISO-8859-15". + * This function fixes this by replacing whitespace with a hyphen. + */ + QString encodingForName( const QString &descriptiveName ); +} + +#endif diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/vcardviewer.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/vcardviewer.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/vcardviewer.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/vcardviewer.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,101 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Daniel Molkentin + + 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) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "vcardviewer.h" +#include "kmaddrbook.h" +#include + +#include +using KPIM::AddresseeView; + +#include +#include +using KABC::VCardConverter; +using KABC::Addressee; + +#include + +#include + +VCardViewer::VCardViewer(QWidget *parent, const QByteArray& vCard) + : KDialog( parent ) +{ + setCaption( i18n("VCard Viewer") ); + setButtons( User1|User2|User3|Close ); + setModal( false ); + setDefaultButton( Close ); + setButtonGuiItem( User1, KGuiItem(i18n("&Import")) ); + setButtonGuiItem( User2, KGuiItem(i18n("&Next Card")) ); + setButtonGuiItem( User3, KGuiItem(i18n("&Previous Card")) ); + mAddresseeView = new AddresseeView(this); + mAddresseeView->enableLinks( 0 ); + mAddresseeView->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded ); + setMainWidget(mAddresseeView); + + VCardConverter vcc; + mAddresseeList = vcc.parseVCards( vCard ); + if ( !mAddresseeList.empty() ) { + itAddresseeList = mAddresseeList.begin(); + mAddresseeView->setAddressee( *itAddresseeList ); + if ( mAddresseeList.size() <= 1 ) { + showButton(User2, false); + showButton(User3, false); + } + else + enableButton(User3, false); + } + else { + mAddresseeView->setPlainText(i18n("Failed to parse vCard.")); + enableButton(User1, false); + } + connect( this, SIGNAL( user1clicked() ), SLOT( slotUser1() ) ); + connect( this, SIGNAL( user2clicked() ), SLOT( slotUser2() ) ); + connect( this, SIGNAL( user3clicked() ), SLOT( slotUser3() ) ); + + resize(300,400); +} + +VCardViewer::~VCardViewer() +{ +} + +void VCardViewer::slotUser1() +{ + KPIM::KAddrBookExternal::addVCard( *itAddresseeList, this ); +} + +void VCardViewer::slotUser2() +{ + // next vcard + mAddresseeView->setAddressee( *(++itAddresseeList) ); + if ( itAddresseeList == --(mAddresseeList.end()) ) + enableButton(User2, false); + enableButton(User3, true); +} + +void VCardViewer::slotUser3() +{ + // previous vcard + mAddresseeView->setAddressee( *(--itAddresseeList) ); + if ( itAddresseeList == mAddresseeList.begin() ) + enableButton(User3, false); + enableButton(User2, true); +} + +#include "vcardviewer.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/vcardviewer.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/vcardviewer.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/vcardviewer.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/vcardviewer.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,51 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Daniel Molkentin + + 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) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef MESSAGEVIEWER_VCARDVIEWER_H +#define MESSAGEVIEWER_VCARDVIEWER_H +#include "messageviewer_export.h" +#include +#include + +namespace KPIM { + class AddresseeView; +} +//(laurent) temporary export until we remove old code in kmail +class MESSAGEVIEWER_EXPORT VCardViewer : public KDialog +{ + Q_OBJECT + public: + VCardViewer(QWidget *parent, const QByteArray& vCard); + virtual ~VCardViewer(); + + protected: + virtual void slotUser1(); + virtual void slotUser2(); + virtual void slotUser3(); + + private: + KPIM::AddresseeView * mAddresseeView; + KABC::Addressee::List mAddresseeList; + + KABC::Addressee::List::Iterator itAddresseeList; +}; + + +#endif // VCARDVIEWER_H + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/viewer.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/viewer.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/viewer.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/viewer.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,448 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + This file is part of KMail, the KDE mail client. + Copyright (c) 1997 Markus Wuebben + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +// define this to copy all html that is written to the readerwindow to +// filehtmlwriter.out in the current working directory +//#define KMAIL_READER_HTML_DEBUG 1 +#include "viewer.h" +#include "viewer_p.h" +#include "configurewidget.h" +#include "csshelper.h" +#include "globalsettings.h" + +//KDE includes +#include +#include + +namespace MessageViewer { + +Viewer::Viewer(QWidget *aParent, + KSharedConfigPtr config, + QWidget *mainWindow, + KActionCollection* actionCollection, + Qt::WindowFlags aFlags ) + : QWidget(aParent, aFlags ), d_ptr(new ViewerPrivate(this, config, mainWindow, actionCollection) ) +{ + connect( d_ptr, SIGNAL( replaceMsgByUnencryptedVersion() ), SIGNAL( replaceMsgByUnencryptedVersion() ) ); + connect( d_ptr, SIGNAL( popupMenu(KMime::Message &, const KUrl &, const QPoint&) ), SIGNAL( popupMenu(KMime::Message &, const KUrl &, const QPoint&) ) ); + connect( d_ptr, SIGNAL( urlClicked(const KUrl&, int ) ), SIGNAL( urlClicked(const KUrl&, int ) ) ); + connect( d_ptr, SIGNAL( noDrag() ), SIGNAL( noDrag() ) ); + setMessage( 0, Delayed ); +} + +Viewer::~Viewer() +{ + //the d_ptr is automatically deleted +} + + +void Viewer::setMessage(KMime::Message* message, UpdateMode updateMode, Ownership ownership) +{ + Q_D(Viewer); + d->setMessage( message, updateMode, ownership); +} + + +void Viewer::setMessageItem(const Akonadi::Item &item, UpdateMode updateMode) +{ + Q_D(Viewer); + d->setMessageItem( item, updateMode ); +} + +void Viewer::displaySplashPage( const QString &info ) +{ + Q_D(Viewer); + d->displaySplashPage( info ); +} + + +void Viewer::enableMessageDisplay() +{ + Q_D(Viewer); + d->enableMessageDisplay(); +} + +void Viewer::printMessage( KMime::Message* message ) +{ + Q_D(Viewer); + d->printMessage( message ); +} + +void Viewer::print() +{ + Q_D(Viewer); + if ( !message() ) + return; + d->mViewer->view()->print(); +} + +void Viewer::resizeEvent( QResizeEvent * ) +{ + Q_D(Viewer); + if( !d->mResizeTimer.isActive() ) + { + // + // Combine all resize operations that are requested as long a + // the timer runs. + // + d->mResizeTimer.start( 100 ); + } +} + +void Viewer::closeEvent( QCloseEvent *e ) +{ + Q_D(Viewer); + QWidget::closeEvent( e ); + d->writeConfig(); +} + +void Viewer::slotScrollUp() +{ + Q_D(Viewer); + d->mViewer->view()->scrollBy( 0, -10 ); +} + +void Viewer::slotScrollDown() +{ + Q_D(Viewer); + d->mViewer->view()->scrollBy( 0, 10 ); +} + +bool Viewer::atBottom() const +{ + Q_D(const Viewer); + KHTMLView *view = d->mViewer->view(); + return view->contentsY() + view->visibleHeight() >= view->contentsHeight(); +} + +void Viewer::slotJumpDown() +{ + Q_D(Viewer); + KHTMLView *view = d->mViewer->view(); + view->scrollBy( 0, view->visibleHeight() ); +} + +void Viewer::slotScrollPrior() +{ + Q_D(Viewer); + KHTMLView *view = d->mViewer->view(); + view->scrollBy( 0, -(int)(d->mViewer->widget()->height() * 0.8 ) ); +} + +void Viewer::slotScrollNext() +{ + Q_D(Viewer); + KHTMLView *view = d->mViewer->view(); + view->scrollBy( 0, (int)(d->mViewer->widget()->height() * 0.8 ) ); +} + +QString Viewer::selectedText() +{ + Q_D(Viewer); + QString temp = d->mViewer->selectedText(); + return temp; +} + +void Viewer::setHtmlOverride( bool override ) +{ + Q_D(Viewer); + d->setHtmlOverride( override ); +} + +bool Viewer::htmlOverride() const +{ + Q_D(const Viewer);; + return d->htmlOverride(); +} + +void Viewer::setHtmlLoadExtOverride( bool override ) +{ + Q_D(Viewer); + d->setHtmlLoadExtOverride( override ); +} + +bool Viewer::htmlLoadExtOverride() const +{ + Q_D(const Viewer); + return d->htmlLoadExtOverride(); +} + +bool Viewer::htmlMail() const +{ + Q_D(const Viewer); + return d->htmlMail(); +} + +bool Viewer::htmlLoadExternal() const +{ + Q_D(const Viewer); + return d->htmlLoadExternal(); +} + +bool Viewer::isFixedFont() const +{ + Q_D(const Viewer); + return d->mUseFixedFont; + +} +void Viewer::setUseFixedFont( bool useFixedFont ) +{ + Q_D(Viewer); + d->setUseFixedFont( useFixedFont ); +} + +QWidget* Viewer::mainWindow() +{ + Q_D(Viewer); + return d->mMainWindow; +} + +void Viewer::setDecryptMessageOverwrite( bool overwrite ) +{ + Q_D(Viewer); + d->setDecryptMessageOverwrite( overwrite ); +} + +bool Viewer::decryptMessage() const +{ + Q_D(const Viewer); + return d->decryptMessage(); +} + +bool Viewer::showSignatureDetails() const +{ + Q_D(const Viewer); + return d->showSignatureDetails(); +} + +void Viewer::setShowSignatureDetails( bool showDetails ) +{ + Q_D(Viewer); + d->setShowSignatureDetails( showDetails ); +} + +bool Viewer::showAttachmentQuicklist() const +{ + Q_D(const Viewer); + return d->showAttachmentQuicklist(); +} + +void Viewer::setShowAttachmentQuicklist( bool showAttachmentQuicklist ) +{ + Q_D(Viewer); + d->setShowAttachmentQuicklist( showAttachmentQuicklist ); +} + +QWidget* Viewer::configWidget() +{ + Q_D(Viewer); + ConfigureWidget *w = new ConfigureWidget(); + connect( w, SIGNAL( settingsChanged() ), d, SLOT( slotSettingsChanged() ) ); + return w; +} + +KConfigSkeleton *Viewer::configObject() +{ + return GlobalSettings::self(); +} + +KMime::Message* Viewer::message() const +{ + Q_D(const Viewer); + return d->mMessage; +} + +void Viewer::setPrintFont( const QFont& font ) +{ + Q_D(Viewer); + d->mCSSHelper->setPrintFont( font ); +} + +void Viewer::styleChange( QStyle& oldStyle ) +{ + Q_D(Viewer); + d->setStyleDependantFrameWidth(); + QWidget::styleChange( oldStyle ); +} + +bool Viewer::event(QEvent *e) +{ + Q_D(Viewer); + if (e->type() == QEvent::PaletteChange) + { + delete d->mCSSHelper; + d->mCSSHelper = new CSSHelper( d->mViewer->view() ); +/*FIXME(Andras) port it + if (message()) + message()->readConfig(); +*/ + d->update( Viewer::Force ); // Force update + return true; + } + return QWidget::event(e); +} + +void Viewer::slotFind() +{ + Q_D(Viewer); + d->mViewer->findText(); +} + +const AttachmentStrategy * Viewer::attachmentStrategy() const +{ + Q_D(const Viewer); + return d->attachmentStrategy(); +} + +void Viewer::setAttachmentStrategy( const AttachmentStrategy * strategy ) +{ + Q_D(Viewer); + d->setAttachmentStrategy( strategy ); +} + +QString Viewer::overrideEncoding() const +{ + Q_D( const Viewer ); + return d->overrideEncoding(); +} + +void Viewer::setOverrideEncoding( const QString &encoding ) +{ + Q_D( Viewer ); + d->setOverrideEncoding( encoding ); + +} + +MessageViewer::CSSHelper* Viewer::cssHelper() const +{ + Q_D( const Viewer ); + return d->cssHelper(); +} + + +KToggleAction *Viewer::toggleFixFontAction() +{ + Q_D( Viewer ); + return d->mToggleFixFontAction; +} + +KToggleAction *Viewer::toggleMimePartTreeAction() +{ + Q_D( Viewer ); + return d->mToggleMimePartTreeAction; +} + +KAction *Viewer::selectAllAction() +{ + Q_D( Viewer ); + return d->mSelectAllAction; +} + +const HeaderStrategy * Viewer::headerStrategy() const +{ + Q_D( const Viewer ); + return d->headerStrategy(); +} + +const HeaderStyle * Viewer::headerStyle() const +{ + Q_D( const Viewer ); + return d->headerStyle(); +} + +void Viewer::setHeaderStyleAndStrategy( const HeaderStyle * style, + const HeaderStrategy * strategy ) +{ + Q_D( Viewer ); + d->setHeaderStyleAndStrategy( style, strategy ); +} + +KHTMLPart *Viewer::htmlPart() const +{ + Q_D( const Viewer ); + return d->htmlPart(); +} + +KAction *Viewer::copyURLAction() +{ + Q_D( Viewer ); + return d->mCopyURLAction; +} + +KAction *Viewer::copyAction() +{ + Q_D( Viewer ); + return d->mCopyAction; +} + +KAction *Viewer::urlOpenAction() +{ + Q_D( Viewer ); + return d->mUrlOpenAction; +} + +void Viewer::setPrinting(bool enable) +{ + Q_D( Viewer ); + d->setPrinting( enable ); +} + +void Viewer::writeConfig( bool force ) const +{ + Q_D( const Viewer ); + d->writeConfig( force ); +} + +void Viewer::slotUrlClicked() +{ + Q_D( Viewer ); + d->slotUrlClicked(); +} + +void Viewer::saveRelativePosition() +{ + Q_D( Viewer ); + d->saveRelativePosition(); +} + +KUrl Viewer::urlClicked() const +{ + Q_D( const Viewer ); + return d->mUrlClicked; +} + +bool Viewer::autoDelete(void) const +{ + Q_D( const Viewer ); + return d->mDeleteMessage; +} + +void Viewer::setAutoDelete(bool f) +{ + Q_D( Viewer ); + d->mDeleteMessage = f; +} + +} + +#include "viewer.moc" + + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/viewer.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/viewer.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/viewer.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/viewer.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,295 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + This file is part of KMail, the KDE mail client. + Copyright (c) 1997 Markus Wuebben + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#ifndef MESSAGEVIEWER_H +#define MESSAGEVIEWER_H + +#include "messageviewer_export.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//Akonadi includes +#include + +class QSplitter; +class KHBox; +class QTreeWidgetItem; +class QString; +class QTextCodec; +class QTreeView; +class QModelIndex; + +class KActionCollection; +class KAction; +class KSelectAction; +class KToggleAction; +class KToggleAction; +class KHTMLPart; +class KUrl; +class KConfigSkeleton; + +namespace { + class AttachmentURLHandler; + class FallBackURLHandler; + class HtmlAnchorHandler; +} + +namespace MessageViewer { + class AttachmentStrategy; + class ViewerPrivate; + class CSSHelper; + class HeaderStrategy; + class HeaderStyle; +} + +/** + This class implements a "reader window", that is a window + used for reading or viewing messages. +*/ + +namespace MessageViewer { +//TODO(Andras) once only those methods are public that really need to be public, probably export the whole class instead of just some methods +class MESSAGEVIEWER_EXPORT Viewer: public QWidget { + Q_OBJECT + Q_DECLARE_PRIVATE(Viewer) + + public: + /** + * Create a mail viewer widget + * @param config a config object from where the configuration is read + * @param parent parent widget + * @param mainWindow the application's main window + * @param actionCollection the action collection where the widget's actions will belong to + * @param f window flags + */ + Viewer( QWidget *parent, KSharedConfigPtr config = KSharedConfigPtr(), QWidget *mainWindow = 0, + KActionCollection *actionCollection = 0, Qt::WindowFlags f = 0 ); + virtual ~Viewer(); + + /** + * Returns the current message displayed in the viewer. + */ + KMime::Message* message() const; //TODO(Andras): convert mMessage to KMime::Message::Ptr ? This is not nice to expose the internal pointer. + + + /** The display update mode: Force updates the display immediately, Delayed updates + after some time (150ms by default */ + enum UpdateMode { + Force = 0, + Delayed + }; + + /** Flag to indicate the owrnership of the message data pointer. Transfer means the ownership is taken + * by the MailViewer class, Keep means it the ownership is not taken. + */ + enum Ownership { + Transfer= 0, + Keep + }; + + /** Set the message that shall be shown. + * @param msg - the message to be shown. If 0, an empty page is displayed. + * @param updateMode - update the display immediately or not. See UpdateMode. + * @param Ownership - Transfer means the ownership of the msg pointer is taken by the lib + */ + void setMessage(KMime::Message* message, UpdateMode updateMode = Delayed, Ownership ownership = Keep); + + /** Set the Akonadi item that will be displayed. + * @param item - the Akonadi item to be displayed. If it doesn't hold a mail (KMime::Message::Ptr as payload data), + * an empty page is shown. + * @param updateMode - update the display immediately or not. See UpdateMode. + */ + void setMessageItem(const Akonadi::Item& item, UpdateMode updateMode = Delayed ); + + /** Convenience method to clear the reader and discard the current message. Sets the internal message pointer + * returned by message() to 0. + * @param updateMode - update the display immediately or not. See UpdateMode. + */ + void clear(UpdateMode updateMode = Delayed ) { setMessage(0, updateMode); } + + /** Sets a message as the current one and print it immediately. + * @param message the message to display and print + */ + void printMessage( KMime::Message* message ); + + /** Print the currently displayed message */ + void print(); + + /** Return selected text */ + QString selectedText(); + + /** Get the html override setting */ + bool htmlOverride() const; + + /** Override default html mail setting */ + void setHtmlOverride( bool override ); + + /** Get the load external references override setting */ + bool htmlLoadExtOverride() const; + +/** Override default load external references setting */ + void setHtmlLoadExtOverride( bool override ); + + /** Is html mail to be supported? Takes into account override */ + bool htmlMail() const; + + /** Is loading ext. references to be supported? Takes into account override */ + bool htmlLoadExternal() const; + + /** Display a generic HTML splash page instead of a message. + * @param info - the text to be displayed in HTML format + */ + void displaySplashPage( const QString& info ); + + /** Enable the displaying of messages again after an splash (or other) page was displayed */ + void enableMessageDisplay(); + + /** Returns true if the message view is scrolled to the bottom. */ + bool atBottom() const; + + bool isFixedFont() const; + void setUseFixedFont( bool useFixedFont ); + + QWidget* mainWindow(); + + /** Enforce message decryption. */ + void setDecryptMessageOverwrite( bool overwrite = true ); + + /** Returns whether the message should be decryted. */ + bool decryptMessage() const; + + /** Show signature details. */ + bool showSignatureDetails() const; + + /** Show signature details. */ + void setShowSignatureDetails( bool showDetails = true ) ; + + /* show or hide the list that points to the attachments */ + bool showAttachmentQuicklist() const; + + /* show or hide the list that points to the attachments */ + void setShowAttachmentQuicklist( bool showAttachmentQuicklist = true ); + + /** + * Get an instance for the configuration widget. The caller has the ownership and must delete the widget. See also configObject(); + * The caller should also call the widget's slotSettingsChanged() if the configuration has changed. + */ + QWidget* configWidget(); + + /** + * Returns the configuration object that can be used in a KConfigDialog together with configWidget(); + */ + KConfigSkeleton *configObject(); + + /** Set the font used for printing. + * @param font the selected font + */ + void setPrintFont( const QFont& font ); + + const AttachmentStrategy * attachmentStrategy() const; + void setAttachmentStrategy( const AttachmentStrategy * strategy ); + + QString overrideEncoding() const; + void setOverrideEncoding( const QString &encoding ); + CSSHelper* cssHelper() const; + void setPrinting(bool enable); + + KToggleAction *toggleFixFontAction(); + + KToggleAction *toggleMimePartTreeAction(); + + KAction *selectAllAction(); + KAction *copyURLAction(); + KAction *copyAction(); + KAction *urlOpenAction(); + + const HeaderStrategy * headerStrategy() const; + + const HeaderStyle * headerStyle() const; + + void setHeaderStyleAndStrategy( const HeaderStyle * style, + const HeaderStrategy * strategy ); + KHTMLPart *htmlPart() const; + + + void writeConfig( bool withSync=true ) const; + + void saveRelativePosition(); + + KUrl urlClicked() const; + + bool autoDelete(void) const; + void setAutoDelete(bool f); + +signals: + /** Emitted after parsing of a message to have it stored + in unencrypted state in it's folder. */ + void replaceMsgByUnencryptedVersion(); + + /** The user presses the right mouse button. 'url' may be 0. */ + void popupMenu(KMime::Message &msg, const KUrl &url, const QPoint& mousePos); + + /** The user has clicked onto an URL that is no attachment. */ + void urlClicked(const KUrl &url, int button); + + /** Pgp displays a password dialog */ + void noDrag(void); + +public slots: + + /** HTML Widget scrollbar and layout handling. */ + void slotScrollUp(); + void slotScrollDown(); + void slotScrollPrior(); + void slotScrollNext(); + void slotJumpDown(); + void slotFind(); + void slotUrlClicked(); + +protected: + /** Some necessary event handling. */ + virtual void closeEvent(QCloseEvent *); + virtual void resizeEvent(QResizeEvent *); + /** reimplemented in order to update the frame width in case of a changed + GUI style */ + void styleChange( QStyle& oldStyle ); + /** Watch for palette changes */ + virtual bool event(QEvent *e); + + ViewerPrivate* const d_ptr; +}; + +} + +#endif + diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/viewer_p.cpp /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/viewer_p.cpp --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/viewer_p.cpp 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/viewer_p.cpp 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,3074 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (c) 1997 Markus Wuebben + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ +//#define MESSAGEVIEWER_READER_HTML_DEBUG 1 +#include "viewer_p.h" +#include "viewer.h" +#include "objecttreeemptysource.h" +#include "objecttreeviewersource.h" + +#ifdef MESSAGEVIEWER_READER_HTML_DEBUG +#include "filehtmlwriter.h" +using MessageViewer::FileHtmlWriter; +#include "teehtmlwriter.h" +using MessageViewer::TeeHtmlWriter; +#endif +#include // link() +#include + +//KDE includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +//Qt includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//libkdepim +#include "libkdepim/broadcaststatus.h" +#include + +//own includes +#include "attachmentdialog.h" +#include "attachmentstrategy.h" +#include "csshelper.h" +#include "editorwatcher.h" +#include "global.h" +#include "globalsettings.h" +#include "headerstyle.h" +#include "headerstrategy.h" +#include "htmlstatusbar.h" +#include "khtmlparthtmlwriter.h" +#include "mailsourceviewer.h" +#include "mimetreemodel.h" +#include "nodehelper.h" +#include "objecttreeparser.h" +#include "stringutil.h" +#include "urlhandlermanager.h" +#include "util.h" +#include "vcardviewer.h" + +#include "interfaces/bodypart.h" +#include "interfaces/htmlwriter.h" + +using namespace MessageViewer; + +const int ViewerPrivate::delay = 150; + +ViewerPrivate::ViewerPrivate(Viewer *aParent, + KSharedConfigPtr config, + QWidget *mainWindow, + KActionCollection* actionCollection) + : QObject(aParent), + mMessage( 0 ), + mAttachmentStrategy( 0 ), + mHeaderStrategy( 0 ), + mHeaderStyle( 0 ), + mUpdateReaderWinTimer( 0 ), + mResizeTimer( 0 ), + mOldGlobalOverrideEncoding( "---" ), // init with dummy value + mCSSHelper( 0 ), + mMainWindow( mainWindow ), + mActionCollection( actionCollection ), + mCopyAction( 0 ), + mCopyURLAction( 0 ), + mUrlOpenAction( 0 ), + mSelectAllAction( 0 ), + mScrollUpAction( 0 ), + mScrollDownAction( 0 ), + mScrollUpMoreAction( 0 ), + mScrollDownMoreAction( 0 ), + mToggleMimePartTreeAction( 0 ), + mSelectEncodingAction( 0 ), + mToggleFixFontAction( 0 ), + mHtmlWriter( 0 ), + mSavedRelativePosition( 0 ), + mDecrytMessageOverwrite( false ), + mShowSignatureDetails( false ), + mShowAttachmentQuicklist( true ), + q( aParent ) +{ + if ( !mainWindow ) + mainWindow = aParent; + + mDeleteMessage = false; + + mHtmlOverride = false; + mHtmlLoadExtOverride = false; + mHtmlLoadExternal = false; + + Global::instance()->setConfig( config ); + GlobalSettings::self()->setSharedConfig( Global::instance()->config() ); + GlobalSettings::self()->readConfig(); //need to re-read the config as the config object might be different than the default mailviewerrc + mUpdateReaderWinTimer.setObjectName( "mUpdateReaderWinTimer" ); + mResizeTimer.setObjectName( "mResizeTimer" ); + + mExternalWindow = ( aParent == mainWindow ); + mSplitterSizes << 180 << 100; + mLastStatus.clear(); + mMsgDisplay = true; + mPrinting = false; + + createWidgets(); + createActions(); + initHtmlWidget(); + readConfig(); + + mLevelQuote = GlobalSettings::self()->collapseQuoteLevelSpin() - 1; + + mResizeTimer.setSingleShot( true ); + connect( &mResizeTimer, SIGNAL(timeout()), + this, SLOT(slotDelayedResize()) ); + + mUpdateReaderWinTimer.setSingleShot( true ); + connect( &mUpdateReaderWinTimer, SIGNAL(timeout()), + this, SLOT(updateReaderWin()) ); + + connect( this, SIGNAL(urlClicked(const KUrl&,int)), + this, SLOT(slotUrlClicked()) ); +} + +ViewerPrivate::~ViewerPrivate() +{ + clearBodyPartMementos(); + delete mHtmlWriter; mHtmlWriter = 0; + delete mCSSHelper; + if ( mDeleteMessage ) + delete mMessage; + mMessage = 0; + NodeHelper::instance()->removeTempFiles(); +} + + + +//----------------------------------------------------------------------------- +KMime::Content * ViewerPrivate::nodeFromUrl( const KUrl & url ) +{ + if ( url.isEmpty() ) + return 0; + if ( !url.isLocalFile() ) + return 0; + + QString path = url.toLocalFile(); + uint right = path.lastIndexOf( '/' ); + uint left = path.lastIndexOf( '.', right ); + + KMime::ContentIndex index(path.mid( left + 1, right - left - 1 )); + KMime::Content *node = mMessage->content( index ); + + return node; +} + +KMime::Content* ViewerPrivate::nodeForContentIndex( const KMime::ContentIndex& index ) +{ + return mMessage->content( index ); +} + + +void ViewerPrivate::openAttachment( KMime::Content* node, const QString & name ) +{ + if( !node ) { + return; + } + + QString atmName = name; + QString str, pname, cmd, fileName; + + if ( name.isEmpty() ) + atmName = NodeHelper::instance()->tempFileUrlFromNode( node ).toLocalFile(); + + if ( node->contentType()->mediaType() == "message" ) + { + atmViewMsg( node ); + return; + } + + // determine the MIME type of the attachment + KMimeType::Ptr mimetype; + // prefer the value of the Content-Type header + mimetype = KMimeType::mimeType( QString::fromLatin1( node->contentType()->mimeType().toLower() ), KMimeType::ResolveAliases ); + if ( !mimetype.isNull() && mimetype->is( KABC::Addressee::mimeType() ) ) { + showVCard( node ); + return; + } + + // special case treatment on mac + if ( Util::handleUrlOnMac( atmName ) ) + return; + + if ( mimetype.isNull() || mimetype->name() == "application/octet-stream" ) { + // consider the filename if mimetype can not be found by content-type + mimetype = KMimeType::findByPath( name, 0, true /* no disk access */ ); + + } + if ( mimetype->name() == "application/octet-stream" ) { + // consider the attachment's contents if neither the Content-Type header + // nor the filename give us a clue + mimetype = KMimeType::findByFileContent( name ); + } + + KService::Ptr offer = + KMimeTypeTrader::self()->preferredService( mimetype->name(), "Application" ); + + QString filenameText = NodeHelper::fileName( node ); + + AttachmentDialog dialog( mMainWindow, filenameText, offer ? offer->name() : QString(), + QString::fromLatin1( "askSave_" ) + mimetype->name() ); + const int choice = dialog.exec(); + + if ( choice == AttachmentDialog::Save ) { + saveAttachments( KMime::Content::List() << node ); + } + else if ( choice == AttachmentDialog::Open ) { // Open + attachmentOpen( node ); + } else if ( choice == AttachmentDialog::OpenWith ) { + attachmentOpenWith( node ); + } else { // Cancel + kDebug() <<"Canceled opening attachment"; + } + +} + +bool ViewerPrivate::deleteAttachment(KMime::Content * node, bool showWarning) +{ + if ( !node ) + return true; + KMime::Content *parent = node->parent(); + if ( !parent ) + return true; + + if ( showWarning && KMessageBox::warningContinueCancel( mMainWindow, + i18n("Deleting an attachment might invalidate any digital signature on this message."), + i18n("Delete Attachment"), KStandardGuiItem::del(), KStandardGuiItem::cancel(), + "DeleteAttachmentSignatureWarning" ) + != KMessageBox::Continue ) { + return false; //cancelled + } + + mMimePartModel->setRoot( 0 ); //don't confuse the model + parent->removeContent( node, true ); + mMimePartModel->setRoot( mMessage ); + + mMessageItem.setPayloadFromData( mMessage->encodedContent() ); + Akonadi::ItemModifyJob *job = new Akonadi::ItemModifyJob( mMessageItem ); +//TODO(Andras) error checking? connect( job, SIGNAL(result(KJob*)), SLOT(imapItemUpdateResult(KJob*)) ); + + return true; +} + +bool ViewerPrivate::editAttachment( KMime::Content * node, bool showWarning ) +{ + //FIXME(Andras) just that I don't forget...handle the case when the user starts editing and switches to another message meantime + if ( showWarning && KMessageBox::warningContinueCancel( mMainWindow, + i18n("Modifying an attachment might invalidate any digital signature on this message."), + i18n("Edit Attachment"), KGuiItem( i18n("Edit"), "document-properties" ), KStandardGuiItem::cancel(), + "EditAttachmentSignatureWarning" ) + != KMessageBox::Continue ) { + return false; + } + + KTemporaryFile file; + file.setAutoRemove( false ); + if ( !file.open() ) { + kWarning() << "Edit Attachment: Unable to open temp file."; + return true; + } + file.write( node->decodedContent() ); + file.flush(); + + MessageViewer::EditorWatcher *watcher = + new MessageViewer::EditorWatcher( KUrl( file.fileName() ), node->contentType()->mimeType(), + false, this, mMainWindow ); + mEditorWatchers[ watcher ] = node; + + connect( watcher, SIGNAL(editDone(MessageViewer::EditorWatcher*)), SLOT(slotAttachmentEditDone(MessageViewer::EditorWatcher*)) ); + if ( !watcher->start() ) { + QFile::remove( file.fileName() ); + } + + return true; +} + + +void ViewerPrivate::showAttachmentPopup( int id, const QString & name, const QPoint &p ) +{ + prepareHandleAttachment( id, name ); + KMenu *menu = new KMenu(); + QAction *action; + + QSignalMapper *attachmentMapper = new QSignalMapper( menu ); + connect( attachmentMapper, SIGNAL( mapped( int ) ), + this, SLOT( slotHandleAttachment( int ) ) ); +/*FIXME(Andras) port to akonadi + QSignalMapper *attachmentMapper = new QSignalMapper( menu ); + connect( attachmentMapper, SIGNAL( mapped( int ) ), + this, SLOT( slotHandleAttachment( int ) ) ); + + action = menu->addAction(SmallIcon("document-open"),i18nc("to open", "Open")); + connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Open ); + + action = menu->addAction(i18n("Open With...")); + connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::OpenWith ); + + action = menu->addAction(i18nc("to view something", "View") ); + connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::View ); + + const bool attachmentInHeader = hasParentDivWithId( mViewer->nodeUnderMouse(), "attachmentInjectionPoint" ); + const bool hasScrollbar = mViewer->view()->verticalScrollBar()->isVisible(); + if ( attachmentInHeader && hasScrollbar ) { + action = menu->addAction( i18n( "Scroll To" ) ); + connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::ScrollTo ); + } + + action = menu->addAction(SmallIcon("document-save-as"),i18n("Save As...") ); + connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Save ); + + action = menu->addAction(SmallIcon("edit-copy"), i18n("Copy") ); + connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Copy ); + + const bool canChange = message()->parent() ? !message()->parent()->isReadOnly() : false; + + if ( GlobalSettings::self()->allowAttachmentEditing() ) { + action = menu->addAction(SmallIcon("document-properties"), i18n("Edit Attachment") ); + connect( action, SIGNAL(triggered()), attachmentMapper, SLOT(map()) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Edit ); + action->setEnabled( canChange ); + } + if ( GlobalSettings::self()->allowAttachmentDeletion() ) { + action = menu->addAction(SmallIcon("edit-delete"), i18n("Delete Attachment") ); + connect( action, SIGNAL(triggered()), attachmentMapper, SLOT(map()) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Delete ); + action->setEnabled( canChange ); + } + if ( name.endsWith( QLatin1String(".xia"), Qt::CaseInsensitive ) && + Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) ) { + action = menu->addAction( i18n( "Decrypt With Chiasmus..." ) ); + connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::ChiasmusEncrypt ); + } + action = menu->addAction(i18n("Properties") ); + connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) ); + attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Properties ); + */ + menu->exec( p ); + delete menu; +} + +Interface::BodyPartMemento *ViewerPrivate::bodyPartMemento( const KMime::Content *node, + const QByteArray &which ) const +{ + const QByteArray index = NodeHelper::path(node) + ':' + which.toLower(); + const QMap::const_iterator it = + mBodyPartMementoMap.find( index ); + + if ( it == mBodyPartMementoMap.end() ) { + return 0; + } else { + return it.value(); + } +} + +void ViewerPrivate::setBodyPartMemento( const KMime::Content *node, + const QByteArray &which, + Interface::BodyPartMemento *memento ) +{ + const QByteArray index = NodeHelper::path(node) + ':' + which.toLower(); + + const QMap::iterator it = + mBodyPartMementoMap.lowerBound( index ); + + if ( it != mBodyPartMementoMap.end() && it.key() == index ) { + if ( memento && memento == it.value() ) { + return; + } + + delete it.value(); + + if ( memento ) { + it.value() = memento; + } else { + mBodyPartMementoMap.erase( it ); + } + } else { + if ( memento ) { + mBodyPartMementoMap.insert( index, memento ); + } + } +} + + +void ViewerPrivate::clearBodyPartMementos() +{ + for ( QMap::iterator + it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end(); + it != end; ++it ) { + delete it.value(); + } + mBodyPartMementoMap.clear(); +} + +void ViewerPrivate::prepareHandleAttachment( int id, const QString& fileName ) +{ + /*TODO(Andras) remove the whole method + mAtmCurrent = id; + mAtmCurrentName = fileName; + */ +} + +// This function returns the complete data that were in this +// message parts - *after* all encryption has been removed that +// could be removed. +// - This is used to store the message in decrypted form. +void ViewerPrivate::objectTreeToDecryptedMsg( KMime::Content* node, + QByteArray& resultingData, + KMime::Message& theMessage, + bool weAreReplacingTheRootNode, + int recCount ) +{ + kDebug() << "-------------------------------------------------"; + kDebug() << "START" << "(" << recCount << ")"; + if( node ) { + KMime::Content* curNode = node; + KMime::Content* dataNode = curNode; + KMime::Content * child = NodeHelper::firstChild( node ); + bool bIsMultipart = false; + + QString type = curNode->contentType()->mediaType(); + QString subType = curNode->contentType()->subType(); + if ( type == "text") { + kDebug() <<"* text *"; + kDebug() << subType; + } else if ( type == "multipart ") { + kDebug() <<"* multipart *"; + kDebug() << subType; + bIsMultipart = true; + if ( subType == "encrypted" ) { + if ( child ) { + /* + ATTENTION: This code is to be replaced by the new 'auto-detect' feature. -------------------------------------- + */ + KMime::Content* data = + ObjectTreeParser::findType( child, "application/octet-stream", false, true ); + if ( !data ) + data = ObjectTreeParser::findType( child, "application/pkcs7-mime", false, true ); + dataNode = NodeHelper::firstChild( data ); + } + } + } else if ( type == "message" ) { + if ( subType == "rfc822") { + if ( child ) + dataNode = child; + } + } else if ( type == "application" ) { + kDebug() <<"* application *"; + kDebug() << subType; + if ( subType == "octet-stream" ) { + if ( child ) + dataNode = child; + } else if ( subType == "pkcs7-mime" ) { + // note: subtype Pkcs7Mime can also be signed + // and we do NOT want to remove the signature! + if ( child && NodeHelper::instance()->encryptionState( curNode ) != KMMsgNotEncrypted ) { + dataNode = child; + } + } + } else if ( type == "image" ) { + kDebug() <<"* image *"; + kDebug() << subType; + } else if ( type == "audio" ) { + kDebug() <<"* audio *"; + kDebug() << subType; + } else if ( type == "video" ) { + kDebug() << "* video *"; + kDebug() << subType; + } else { + kDebug() << type; + kDebug() << subType; + } + + KMime::Content* headerContent = 0; + if ( !dataNode->head().isEmpty() ) { + headerContent = dataNode; + } + if ( weAreReplacingTheRootNode || !dataNode->parent() ) { + headerContent = &theMessage; + } + if( dataNode == curNode ) { + kDebug() <<"dataNode == curNode: Save curNode without replacing it."; + + // A) Store the headers of this part IF curNode is not the root node + // AND we are not replacing a node that already *has* replaced + // the root node in previous recursion steps of this function... + if ( !headerContent->head().isEmpty() ) { + if( dataNode->parent() && !weAreReplacingTheRootNode ) { + kDebug() <<"dataNode is NOT replacing the root node: Store the headers."; + resultingData += headerContent->head(); + } else if( weAreReplacingTheRootNode && !dataNode->head().isEmpty() ){ + kDebug() <<"dataNode replace the root node: Do NOT store the headers but change"; + kDebug() <<" the Message's headers accordingly."; + kDebug() <<" old Content-Type =" << theMessage.contentType()->asUnicodeString(); + kDebug() <<" new Content-Type =" << headerContent->contentType()->asUnicodeString(); + theMessage.contentType()->from7BitString( headerContent->contentType()->as7BitString() ); + theMessage.contentTransferEncoding()->from7BitString( + headerContent->contentTransferEncoding(false) + ? headerContent->contentTransferEncoding()->as7BitString() + : "" ); + theMessage.contentDescription()->from7BitString( headerContent->contentDescription()->as7BitString() ); + theMessage.contentDisposition()->from7BitString( headerContent->contentDisposition()->as7BitString() ); + theMessage.assemble(); + } + } + + // B) Store the body of this part. + if( headerContent && bIsMultipart && !dataNode->contents().isEmpty() ) { + kDebug() <<"is valid Multipart, processing children:"; + QByteArray boundary = headerContent->contentType()->boundary(); + curNode = NodeHelper::firstChild( dataNode ); + // store children of multipart + while( curNode ) { + kDebug() <<"--boundary"; + if( resultingData.size() && + ( '\n' != resultingData.at( resultingData.size()-1 ) ) ) + resultingData += '\n'; + resultingData += '\n'; + resultingData += "--"; + resultingData += boundary; + resultingData += '\n'; + // note: We are processing a harmless multipart that is *not* + // to be replaced by one of it's children, therefor + // we set their doStoreHeaders to true. + objectTreeToDecryptedMsg( curNode, + resultingData, + theMessage, + false, + recCount + 1 ); + curNode = NodeHelper::nextSibling( curNode ); + } + kDebug() <<"--boundary--"; + resultingData += "\n--"; + resultingData += boundary; + resultingData += "--\n\n"; + kDebug() <<"Multipart processing children - DONE"; + } else { + // store simple part + kDebug() <<"is Simple part or invalid Multipart, storing body data .. DONE"; + resultingData += dataNode->body(); + } + } else { + kDebug() <<"dataNode != curNode: Replace curNode by dataNode."; + bool rootNodeReplaceFlag = weAreReplacingTheRootNode || !curNode->parent(); + if( rootNodeReplaceFlag ) { + kDebug() <<" Root node will be replaced."; + } else { + kDebug() <<" Root node will NOT be replaced."; + } + // store special data to replace the current part + // (e.g. decrypted data or embedded RfC 822 data) + objectTreeToDecryptedMsg( dataNode, + resultingData, + theMessage, + rootNodeReplaceFlag, + recCount + 1 ); + } + } + kDebug() << "END" << "(" << recCount << ")"; +} + + +QString ViewerPrivate::createAtmFileLink( const QString& atmFileName ) const +{ + QFileInfo atmFileInfo( atmFileName ); + + KTemporaryFile *linkFile = new KTemporaryFile(); + linkFile->setPrefix( atmFileInfo.fileName() +"_[" ); + linkFile->setSuffix( "]." + KMimeType::extractKnownExtension( atmFileInfo.fileName() ) ); + linkFile->open(); + QString linkName = linkFile->fileName(); + delete linkFile; + + if ( ::link(QFile::encodeName( atmFileName ), QFile::encodeName( linkName )) == 0 ) { + return linkName; // success + } + return QString(); +} + +KService::Ptr ViewerPrivate::getServiceOffer( KMime::Content *content) +{ + QString fileName = NodeHelper::instance()->writeNodeToTempFile( content ); + + const QString contentTypeStr = content->contentType()->mimeType(); + + // determine the MIME type of the attachment + KMimeType::Ptr mimetype; + // prefer the value of the Content-Type header + mimetype = KMimeType::mimeType( contentTypeStr, KMimeType::ResolveAliases ); + + if ( !mimetype.isNull() && mimetype->is( KABC::Addressee::mimeType() ) ) { + slotAtmView( content ); + return KService::Ptr( 0 ); + } + + if ( mimetype.isNull() ) { + // consider the filename if mimetype can not be found by content-type + mimetype = KMimeType::findByPath( fileName, 0, true /* no disk access */ ); + } + if ( ( mimetype->name() == "application/octet-stream" ) + /*TODO(Andris) port when on-demand loading is done && msgPart.isComplete() */) { + // consider the attachment's contents if neither the Content-Type header + // nor the filename give us a clue + mimetype = KMimeType::findByFileContent( fileName ); + } + return KMimeTypeTrader::self()->preferredService( mimetype->name(), "Application" ); +} + +bool ViewerPrivate::saveContent( KMime::Content* content, const KUrl& url, bool encoded ) +{ + KMime::Content *topContent = content->topLevel(); + bool bSaveEncrypted = false; + + bool bEncryptedParts = NodeHelper::instance()->encryptionState( content ) != KMMsgNotEncrypted; + if( bEncryptedParts ) + if( KMessageBox::questionYesNo( mMainWindow, + i18n( "The part %1 of the message is encrypted. Do you want to keep the encryption when saving?", + url.fileName() ), + i18n( "KMail Question" ), KGuiItem(i18n("Keep Encryption")), KGuiItem(i18n("Do Not Keep")) ) == + KMessageBox::Yes ) + bSaveEncrypted = true; + + bool bSaveWithSig = true; + if( NodeHelper::instance()->signatureState( content ) != KMMsgNotSigned ) + if( KMessageBox::questionYesNo( mMainWindow, + i18n( "The part %1 of the message is signed. Do you want to keep the signature when saving?", + url.fileName() ), + i18n( "KMail Question" ), KGuiItem(i18n("Keep Signature")), KGuiItem(i18n("Do Not Keep")) ) != + KMessageBox::Yes ) + bSaveWithSig = false; + + QByteArray data; + if ( encoded ) + { + // This does not decode the Message Content-Transfer-Encoding + // but saves the _original_ content of the message part + data = content->encodedContent(); + } + else + { + if( bSaveEncrypted || !bEncryptedParts) { + KMime::Content *dataNode = content; + QByteArray rawReplyString; + bool gotRawReplyString = false; + if ( !bSaveWithSig ) { + if ( topContent->contentType()->mimeType() == "multipart/signed" ) { + // carefully look for the part that is *not* the signature part: + if ( ObjectTreeParser::findType( topContent, "application/pgp-signature", true, false ) ) { + dataNode = ObjectTreeParser::findTypeNot( topContent, "application", "pgp-signature", true, false ); + } else if ( ObjectTreeParser::findType( topContent, "application/pkcs7-mime" , true, false ) ) { + dataNode = ObjectTreeParser::findTypeNot( topContent, "application", "pkcs7-mime", true, false ); + } else { + dataNode = ObjectTreeParser::findTypeNot( topContent, "multipart", "", true, false ); + } + } else { + EmptySource emptySource; + ObjectTreeParser otp( &emptySource, 0, false, false, false ); + + // process this node and all it's siblings and descendants + NodeHelper::instance()->setNodeUnprocessed( dataNode, true ); + otp.parseObjectTree( dataNode ); + + rawReplyString = otp.rawReplyString(); + gotRawReplyString = true; + } + } + QByteArray cstr = gotRawReplyString + ? rawReplyString + : dataNode->decodedContent(); + data = KMime::CRLFtoLF( cstr ); + } + } + QDataStream ds; + QFile file; + KTemporaryFile tf; + if ( url.isLocalFile() ) + { + // save directly + file.setFileName( url.toLocalFile() ); + if ( !file.open( QIODevice::WriteOnly ) ) + { + KMessageBox::error( mMainWindow, + i18nc( "1 = file name, 2 = error string", + "Could not write to the file
%1

%2", + file.fileName(), + QString::fromLocal8Bit( strerror( errno ) ) ), + i18n( "Error saving attachment" ) ); + return false; + } + +/*FIXME(Andras) port it + // #79685 by default use the umask the user defined, but let it be configurable + if ( GlobalSettings::self()->disregardUmask() ) + fchmod( file.handle(), S_IRUSR | S_IWUSR ); +*/ + ds.setDevice( &file ); + } else + { + // tmp file for upload + tf.open(); + ds.setDevice( &tf ); + } + + if ( ds.writeRawData( data.data(), data.size() ) == -1) + { + QFile *f = static_cast( ds.device() ); + KMessageBox::error( mMainWindow, + i18nc( "1 = file name, 2 = error string", + "Could not write to the file
%1

%2", + f->fileName(), + f->errorString() ), + i18n( "Error saving attachment" ) ); + return false; + } + + if ( !url.isLocalFile() ) + { + // QTemporaryFile::fileName() is only defined while the file is open + QString tfName = tf.fileName(); + tf.close(); + if ( !KIO::NetAccess::upload( tfName, url, mMainWindow ) ) + { + KMessageBox::error( mMainWindow, + i18nc( "1 = file name, 2 = error string", + "Could not write to the file
%1

%2", + url.prettyUrl(), + KIO::NetAccess::lastErrorString() ), + i18n( "Error saving attachment" ) ); + return false; + } + } else + file.close(); + return true; +} + + +void ViewerPrivate::saveAttachments( const KMime::Content::List & contents ) +{ + KUrl url, dirUrl; + if ( contents.size() > 1 ) { + dirUrl = KFileDialog::getExistingDirectoryUrl( KUrl( "kfiledialog:///saveAttachment" ), + mMainWindow, + i18n( "Save Attachments To" ) ); + if ( !dirUrl.isValid() ) { + return; + } + // we may not get a slash-terminated url out of KFileDialog + dirUrl.adjustPath( KUrl::AddTrailingSlash ); + } else { + // only one item, get the desired filename + KMime::Content *content = contents[0]; + // replace all ':' with '_' because ':' isn't allowed on FAT volumes + QString s = content->contentDisposition()->filename().trimmed().replace( ':', '_' ); + if ( s.isEmpty() ) + s = content->contentType()->name().trimmed().replace( ':', '_' ); + if ( s.isEmpty() ) + s = i18nc("filename for an unnamed attachment", "attachment.1"); + url = KFileDialog::getSaveUrl( KUrl( "kfiledialog:///saveAttachment/" + s ), + QString(), + mMainWindow, + i18n( "Save Attachment" ) ); + if ( url.isEmpty() ) { + return; + } + } + + QMap< QString, int > renameNumbering; + + int unnamedAtmCount = 0; + bool overwriteAll = false; + for ( KMime::Content::List::const_iterator it = contents.constBegin(); + it != contents.constEnd(); + ++it ) { + KMime::Content *content = *it; + KUrl curUrl; + if ( !dirUrl.isEmpty() ) { + curUrl = dirUrl; + QString s = content->contentDisposition()->filename(); + if ( s.isEmpty() ) + s = content->contentType()->name().trimmed().replace( ':', '_' ); + if ( s.isEmpty() ) { + ++unnamedAtmCount; + s = i18nc("filename for the %1-th unnamed attachment", + "attachment.%1", + unnamedAtmCount ); + } + curUrl.setFileName( s ); + } else { + curUrl = url; + } + + if ( !curUrl.isEmpty() ) { + + // Rename the file if we have already saved one with the same name: + // try appending a number before extension (e.g. "pic.jpg" => "pic_2.jpg") + QString origFile = curUrl.fileName(); + QString file = origFile; + + while ( renameNumbering.contains(file) ) { + file = origFile; + int num = renameNumbering[file] + 1; + int dotIdx = file.lastIndexOf('.'); + file = file.insert( (dotIdx>=0) ? dotIdx : file.length(), QString("_") + QString::number(num) ); + } + curUrl.setFileName(file); + + // Increment the counter for both the old and the new filename + if ( !renameNumbering.contains(origFile)) + renameNumbering[origFile] = 1; + else + renameNumbering[origFile]++; + + if ( file != origFile ) { + if ( !renameNumbering.contains(file)) + renameNumbering[file] = 1; + else + renameNumbering[file]++; + } + + + if ( !overwriteAll && KIO::NetAccess::exists( curUrl, KIO::NetAccess::DestinationSide, mMainWindow ) ) { + if ( contents.count() == 1 ) { + if ( KMessageBox::warningContinueCancel( mMainWindow, + i18n( "A file named
%1
already exists.

Do you want to overwrite it?", + curUrl.fileName() ), + i18n( "File Already Exists" ), KGuiItem(i18n("&Overwrite")) ) == KMessageBox::Cancel) { + continue; + } + } + else { + int button = KMessageBox::warningYesNoCancel( + mMainWindow, + i18n( "A file named
%1
already exists.

Do you want to overwrite it?", + curUrl.fileName() ), + i18n( "File Already Exists" ), KGuiItem(i18n("&Overwrite")), + KGuiItem(i18n("Overwrite &All")) ); + if ( button == KMessageBox::Cancel ) + continue; + else if ( button == KMessageBox::No ) + overwriteAll = true; + } + } + // save + saveContent( content, curUrl, false ); + } + } +} + +KMime::Content::List ViewerPrivate::allContents( const KMime::Content * content ) +{ + KMime::Content::List result; + KMime::Content *child = NodeHelper::firstChild( content ); + if ( child ) { + result += child; + result += allContents( child ); + } + KMime::Content *next = NodeHelper::nextSibling( content ); + if ( next ) { + result += next; + result += allContents( next ); + } + + return result; +} + + +KMime::Content::List ViewerPrivate::selectedContents() +{ + KMime::Content::List contents; + QItemSelectionModel *selectionModel = mMimePartTree->selectionModel(); + QModelIndexList selectedRows = selectionModel->selectedRows(); + + Q_FOREACH(QModelIndex index, selectedRows) + { + KMime::Content *content = static_cast( index.internalPointer() ); + if ( content ) + contents.append( content ); + } + + return contents; +} + + +void ViewerPrivate::attachmentOpenWith( KMime::Content *node ) +{ + QString name = NodeHelper::instance()->writeNodeToTempFile( node ); + QString linkName = createAtmFileLink( name ); + KUrl::List lst; + KUrl url; + bool autoDelete = true; + + if ( linkName.isEmpty() ) { + autoDelete = false; + linkName = name; + } + + url.setPath( linkName ); + lst.append( url ); + if ( (! KRun::displayOpenWithDialog(lst, mMainWindow, autoDelete)) && autoDelete ) { + QFile::remove( url.toLocalFile() ); + } +} + +void ViewerPrivate::attachmentOpen( KMime::Content *node ) +{ + KService::Ptr offer(0); + offer = getServiceOffer( node ); + if ( !offer ) { + kDebug() << "got no offer"; + return; + } + QString name = NodeHelper::instance()->writeNodeToTempFile( node ); + KUrl::List lst; + KUrl url; + bool autoDelete = true; + QString fname = createAtmFileLink( name ); + + if ( fname.isNull() ) { + autoDelete = false; + fname = name; + } + + url.setPath( fname ); + lst.append( url ); + if ( (!KRun::run( *offer, lst, 0, autoDelete )) && autoDelete ) { + QFile::remove(url.toLocalFile()); + } +} + + +CSSHelper* ViewerPrivate::cssHelper() const +{ + return mCSSHelper; +} + +bool ViewerPrivate::decryptMessage() const +{ + if ( !GlobalSettings::self()->alwaysDecrypt() ) + return mDecrytMessageOverwrite; + else + return true; +} + + +void ViewerPrivate::setStyleDependantFrameWidth() +{ + if ( !mBox ) + return; + // set the width of the frame to a reasonable value for the current GUI style + int frameWidth; +#if 0 // is this hack still needed with kde4? + if( !qstrcmp( style()->metaObject()->className(), "KeramikStyle" ) ) + frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1; + else +#endif + frameWidth = q->style()->pixelMetric( QStyle::PM_DefaultFrameWidth ); + if ( frameWidth < 0 ) + frameWidth = 0; + if ( frameWidth != mBox->lineWidth() ) + mBox->setLineWidth( frameWidth ); +} + + +int ViewerPrivate::pointsToPixel(int pointSize) const +{ + return (pointSize * mViewer->view()->logicalDpiY() + 36) / 72; +} + +void ViewerPrivate::displaySplashPage( const QString &info ) +{ + mMsgDisplay = false; + adjustLayout(); + + QString location = KStandardDirs::locate("data", "kmail/about/main.html");//FIXME(Andras) copy to $KDEDIR/share/apps/mailviewer + QString content = KPIMUtils::kFileToByteArray( location ); + content = content.arg( KStandardDirs::locate( "data", "kdeui/about/kde_infopage.css" ) ); + if ( QApplication::isRightToLeft() ) + content = content.arg( "@import \"" + KStandardDirs::locate( "data", + "kdeui/about/kde_infopage_rtl.css" ) + "\";"); + else + content = content.arg( "" ); + + mViewer->begin(KUrl::fromPath( location )); + + QString fontSize = QString::number( pointsToPixel( mCSSHelper->bodyFont().pointSize() ) ); + QString appTitle = i18n("Mailreader"); + QString catchPhrase = ""; //not enough space for a catch phrase at default window size i18n("Part of the Kontact Suite"); + QString quickDescription = i18n("The email client for the K Desktop Environment."); + mViewer->write(content.arg(fontSize).arg(appTitle).arg(catchPhrase).arg(quickDescription).arg(info)); + mViewer->end(); +} + +void ViewerPrivate::enableMessageDisplay() +{ + mMsgDisplay = true; + adjustLayout(); +} + + + +void ViewerPrivate::displayMessage() +{ + + /*FIXME(Andras) port to Akonadi + mMimePartTree->clearAndResetSortOrder(); + */ + mMimePartModel->setRoot( mMessage ); + showHideMimeTree(); + + NodeHelper::instance()->setOverrideCodec( mMessage, overrideCodec() ); + + htmlWriter()->begin( mCSSHelper->cssDefinitions( mUseFixedFont ) ); + htmlWriter()->queue( mCSSHelper->htmlHead( mUseFixedFont ) ); + + if ( !mMainWindow ) + q->setWindowTitle( mMessage->subject()->asUnicodeString() ); + + NodeHelper::instance()->removeTempFiles(); + + mColorBar->setNeutralMode(); + + parseMsg(); + + if( mColorBar->isNeutral() ) + mColorBar->setNormalMode(); + + htmlWriter()->queue(""); + htmlWriter()->flush(); + + QTimer::singleShot( 1, this, SLOT(injectAttachments()) ); +} + + +void ViewerPrivate::parseMsg() +{ + assert( mMessage != 0 ); + + NodeHelper::instance()->setNodeBeingProcessed( mMessage, true ); + + QString cntDesc = i18n("( body part )"); + + if ( mMessage->subject( false ) ) + cntDesc = mMessage->subject()->asUnicodeString(); + + KIO::filesize_t cntSize = mMessage->size(); + + QString cntEnc= "7bit"; + if ( mMessage->contentTransferEncoding( false ) ) + cntEnc = mMessage->contentTransferEncoding()->asUnicodeString(); + +// Check if any part of this message is a v-card +// v-cards can be either text/x-vcard or text/directory, so we need to check +// both. + KMime::Content* vCardContent = findContentByType( mMessage, "text/x-vcard" ); + if ( !vCardContent ) + vCardContent = findContentByType( mMessage, "text/directory" ); + + bool hasVCard = false; + + if( vCardContent ) { + // ### FIXME: We should only do this if the vCard belongs to the sender, + // ### i.e. if the sender's email address is contained in the vCard. + const QByteArray vCard = vCardContent->decodedContent(); + KABC::VCardConverter t; + if ( !t.parseVCards( vCard ).isEmpty() ) { + hasVCard = true; + kDebug() <<"FOUND A VALID VCARD"; + NodeHelper::instance()->writeNodeToTempFile( vCardContent ); + } + } + htmlWriter()->queue( writeMsgHeader( mMessage, hasVCard ? vCardContent : 0, true ) ); + + // show message content + MailViewerSource otpSource( this ); + ObjectTreeParser otp( &otpSource ); + otp.setAllowAsync( true ); + otp.parseObjectTree( mMessage ); + + bool emitReplaceMsgByUnencryptedVersion = false; + + // store encrypted/signed status information in the KMMessage + // - this can only be done *after* calling parseObjectTree() + KMMsgEncryptionState encryptionState = NodeHelper::instance()->overallEncryptionState( mMessage ); + KMMsgSignatureState signatureState = NodeHelper::instance()->overallSignatureState( mMessage ); + NodeHelper::instance()->setEncryptionState( mMessage, encryptionState ); + // Don't reset the signature state to "not signed" (e.g. if one canceled the + // decryption of a signed messages which has already been decrypted before). + if ( signatureState != KMMsgNotSigned || + NodeHelper::instance()->signatureState( mMessage ) == KMMsgSignatureStateUnknown ) { + NodeHelper::instance()->setSignatureState( mMessage, signatureState ); + } + + const KConfigGroup reader( Global::instance()->config(), "Reader" ); + if ( reader.readEntry( "store-displayed-messages-unencrypted", false ) ) { + + // Hack to make sure the S/MIME CryptPlugs follows the strict requirement + // of german government: + // --> All received encrypted messages *must* be stored in unencrypted form + // after they have been decrypted once the user has read them. + // ( "Aufhebung der Verschluesselung nach dem Lesen" ) + // + // note: Since there is no configuration option for this, we do that for + // all kinds of encryption now - *not* just for S/MIME. + // This could be changed in the objectTreeToDecryptedMsg() function + // by deciding when (or when not, resp.) to set the 'dataNode' to + // something different than 'curNode'. + + +kDebug() <<"\n\n\nSpecial post-encryption handling:\n1."; +//FIXME(Andras) do we need it? kDebug() <<"(aMsg == msg) =" << (aMsg == message()); +kDebug() <<" mLastStatus.isOfUnknownStatus() =" << mLastStatus.isOfUnknownStatus(); +kDebug() <<"|| mLastStatus.isNew() =" << mLastStatus.isNew(); +kDebug() <<"|| mLastStatus.isUnread) =" << mLastStatus.isUnread(); +//FIXME(Andras) kDebug() <<"(mIdOfLastViewedMessage != aMsg->msgId()) =" << (mIdOfLastViewedMessage != aMsg->msgId()); +kDebug() <<" (KMMsgFullyEncrypted == encryptionState) =" << (KMMsgFullyEncrypted == encryptionState); +kDebug() <<"|| (KMMsgPartiallyEncrypted == encryptionState) =" << (KMMsgPartiallyEncrypted == encryptionState); + // only proceed if we were called the normal way - not by + // double click on the message (==not running in a separate window) + if( (/*aMsg == message()*/ true) //TODO(Andras) review if still needed + // only proceed if this message was not saved encryptedly before + // to make sure only *new* messages are saved in decrypted form + && ( mLastStatus.isOfUnknownStatus() + || mLastStatus.isNew() + || mLastStatus.isUnread() ) + // avoid endless recursions +//FIXME(Andras) && (mIdOfLastViewedMessage != aMsg->msgId()) + // only proceed if this message is (at least partially) encrypted + && ( (KMMsgFullyEncrypted == encryptionState) + || (KMMsgPartiallyEncrypted == encryptionState) ) ) { + + kDebug() <<"Calling objectTreeToDecryptedMsg()"; + + KMime::Message *unencryptedMessage = new KMime::Message; + QByteArray decryptedData; + // note: The following call may change the message's headers. + objectTreeToDecryptedMsg( mMessage, decryptedData, *unencryptedMessage ); + kDebug() << "Resulting data:" << decryptedData; + + if( !decryptedData.isEmpty() ) { + kDebug() <<"Composing unencrypted message"; + unencryptedMessage->setBody( decryptedData ); + //FIXME(Andras) fix it? kDebug() << "Resulting message:" << unencryptedMessage->asString(); + kDebug() << "Attach unencrypted message to aMsg"; + + NodeHelper::instance()->attachUnencryptedMessage( mMessage, unencryptedMessage ); + + emitReplaceMsgByUnencryptedVersion = true; + } + } + } + + // store message id to avoid endless recursions +/*FIXME(Andras) port it + setIdOfLastViewedMessage( aMsg->index().toString() ); +*/ + if( emitReplaceMsgByUnencryptedVersion ) { + kDebug() << "Invoce saving in decrypted form:"; + emit replaceMsgByUnencryptedVersion(); //FIXME(Andras) actually connect and do the replacement on the server (see KMMainWidget::slotReplaceByUnencryptedVersion) + } else { + showHideMimeTree(); + } + NodeHelper::instance()->setNodeBeingProcessed( mMessage, false ); +} + + +QString ViewerPrivate::writeMsgHeader(KMime::Message* aMsg, KMime::Content* vCardNode, bool topLevel) +{ + kFatal( !headerStyle(), 5006 ) + << "trying to writeMsgHeader() without a header style set!"; + kFatal( !headerStrategy(), 5006 ) + << "trying to writeMsgHeader() without a header strategy set!"; + QString href; + if ( vCardNode ) + href = NodeHelper::asHREF( vCardNode, "body" ); + + return headerStyle()->format( aMsg, headerStrategy(), href, mPrinting, topLevel ); +} + +void ViewerPrivate::showVCard( KMime::Content* msgPart ) { + const QByteArray vCard = msgPart->decodedContent(); + + VCardViewer *vcv = new VCardViewer( mMainWindow, vCard ); + vcv->setObjectName( "vCardDialog" ); + vcv->show(); +} + + +void ViewerPrivate::initHtmlWidget(void) +{ + mViewer->widget()->setFocusPolicy(Qt::WheelFocus); + // Let's better be paranoid and disable plugins (it defaults to enabled): + mViewer->setPluginsEnabled(false); + mViewer->setJScriptEnabled(false); // just make this explicit + mViewer->setJavaEnabled(false); // just make this explicit + mViewer->setMetaRefreshEnabled(false); + mViewer->setURLCursor( QCursor( Qt::PointingHandCursor ) ); + // Espen 2000-05-14: Getting rid of thick ugly frames + mViewer->view()->setLineWidth(0); + // register our own event filter for shift-click + mViewer->view()->viewport()->installEventFilter( this ); + + if ( !htmlWriter() ) { + mPartHtmlWriter = new KHtmlPartHtmlWriter( mViewer, 0 ); +#ifdef MESSAGEVIEWER_READER_HTML_DEBUG + mHtmlWriter = new TeeHtmlWriter( new FileHtmlWriter( QString() ), + mPartHtmlWriter ); +#else + mHtmlWriter = mPartHtmlWriter; +#endif + } + + // We do a queued connection below, and for that we need to register the meta types of the + // parameters. + // + // Why do we do a queued connection instead of a direct one? slotUrlOpen() handles those clicks, + // and can end up in the click handler for accepting invitations. That handler can pop up a dialog + // asking the user for a comment on the invitation reply. This dialog is started with exec(), i.e. + // executes a sub-eventloop. This sub-eventloop then eventually re-enters the KHTML event handler, + // which then thinks we started a drag, and therefore adds a silly drag object to the cursor, with + // urls like x-kmail-whatever/43/8/accept, and we don't want that drag object. + // + // Therefore, use queued connections to avoid the reentry of the KHTML event loop, so we don't + // get the drag object. + static bool metaTypesRegistered = false; + if ( !metaTypesRegistered ) { + qRegisterMetaType( "KParts::OpenUrlArguments" ); + qRegisterMetaType( "KParts::BrowserArguments" ); + metaTypesRegistered = true; + } + + connect(mViewer->browserExtension(), + SIGNAL(openUrlRequest(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),this, + SLOT(slotUrlOpen(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)), + Qt::QueuedConnection); + connect(mViewer->browserExtension(), + SIGNAL(createNewWindow(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),this, + SLOT(slotUrlOpen(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)), + Qt::QueuedConnection); + connect(mViewer,SIGNAL(onURL(const QString &)),this, + SLOT(slotUrlOn(const QString &))); + connect(mViewer,SIGNAL(popupMenu(const QString &, const QPoint &)), + SLOT(slotUrlPopup(const QString &, const QPoint &))); +} + +bool ViewerPrivate::eventFilter( QObject *, QEvent *e ) +{ + if ( e->type() == QEvent::MouseButtonPress ) { + QMouseEvent* me = static_cast(e); + if ( me->button() == Qt::LeftButton && ( me->modifiers() & Qt::ShiftModifier ) ) { + // special processing for shift+click + KMime::Content *node = nodeFromUrl( mUrlClicked ); + if ( node ) { + saveAttachments( KMime::Content::List() << node); + } + return true; // eat event + } + } + // standard event processing + return false; +} + + +void ViewerPrivate::readConfig() +{ + const KConfigGroup mdnGroup(Global::instance()->config(), "MDN"); + KConfigGroup reader(Global::instance()->config(), "Reader"); + + delete mCSSHelper; + mCSSHelper = new CSSHelper( mViewer->view() ); + + mNoMDNsWhenEncrypted = mdnGroup.readEntry( "not-send-when-encrypted", true ); + + mUseFixedFont = reader.readEntry( "useFixedFont", false ); + if ( mToggleFixFontAction ) + mToggleFixFontAction->setChecked( mUseFixedFont ); + + mHtmlMail = reader.readEntry( "htmlMail", false ); + mHtmlLoadExternal = reader.readEntry( "htmlLoadExternal", false ); + + KToggleAction *raction = actionForHeaderStyle( headerStyle(), headerStrategy() ); + if ( raction ) + raction->setChecked( true ); + + setAttachmentStrategy( AttachmentStrategy::create( reader.readEntry( "attachment-strategy", "smart" ) ) ); + raction = actionForAttachmentStrategy( attachmentStrategy() ); + if ( raction ) + raction->setChecked( true ); + + const int mimeH = reader.readEntry( "MimePaneHeight", 100 ); + const int messageH = reader.readEntry( "MessagePaneHeight", 180 ); + mSplitterSizes.clear(); + if ( GlobalSettings::self()->mimeTreeLocation() == GlobalSettings::EnumMimeTreeLocation::bottom ) + mSplitterSizes << messageH << mimeH; + else + mSplitterSizes << mimeH << messageH; + + adjustLayout(); + + readGlobalOverrideCodec(); + + // Note that this call triggers an update, see this call has to be at the + // bottom when all settings are already est. + setHeaderStyleAndStrategy( HeaderStyle::create( reader.readEntry( "header-style", "fancy" ) ), + HeaderStrategy::create( reader.readEntry( "header-set-displayed", "rich" ) ) ); + + if ( mMessage ) + update(); + mColorBar->update(); + /*FIXME(Andras) + KMMessage::readConfig(); + */ +} + + +void ViewerPrivate::writeConfig( bool sync ) const +{ + KConfigGroup reader( Global::instance()->config() , "Reader" ); + + reader.writeEntry( "useFixedFont", mUseFixedFont ); + if ( headerStyle() ) + reader.writeEntry( "header-style", headerStyle()->name() ); + if ( headerStrategy() ) + reader.writeEntry( "header-set-displayed", headerStrategy()->name() ); + if ( attachmentStrategy() ) + reader.writeEntry( "attachment-strategy", attachmentStrategy()->name() ); + + saveSplitterSizes( reader ); +/*FIXME(Andras) port to akonadi + if ( sync ) + kmkernel->slotRequestConfigSync(); + */ +} + + +void ViewerPrivate::setHeaderStyleAndStrategy( const HeaderStyle * style, + const HeaderStrategy * strategy ) { + mHeaderStyle = style ? style : HeaderStyle::fancy(); + mHeaderStrategy = strategy ? strategy : HeaderStrategy::rich(); + update( Viewer::Force ); +} + + +void ViewerPrivate::setAttachmentStrategy( const AttachmentStrategy * strategy ) { + mAttachmentStrategy = strategy ? strategy : AttachmentStrategy::smart(); + update( Viewer::Force ); +} + + +void ViewerPrivate::setOverrideEncoding( const QString & encoding ) +{ + if ( encoding == mOverrideEncoding ) + return; + + mOverrideEncoding = encoding; + if ( mSelectEncodingAction ) { + if ( encoding.isEmpty() ) { + mSelectEncodingAction->setCurrentItem( 0 ); + } + else { + QStringList encodings = mSelectEncodingAction->items(); + int i = 0; + for ( QStringList::const_iterator it = encodings.constBegin(), end = encodings.constEnd(); it != end; ++it, ++i ) { + if ( ViewerPrivate::encodingForName( *it ) == encoding ) { + mSelectEncodingAction->setCurrentItem( i ); + break; + } + } + if ( i == encodings.size() ) { + // the value of encoding is unknown => use Auto + kWarning() <<"Unknown override character encoding \"" << encoding + << "\". Using Auto instead."; + mSelectEncodingAction->setCurrentItem( 0 ); + mOverrideEncoding.clear(); + } + } + } + update( Viewer::Force ); +} + + +void ViewerPrivate::setPrintFont( const QFont& font ) +{ + + mCSSHelper->setPrintFont( font ); +} + + +void ViewerPrivate::printMessage( KMime::Message* message ) +{ + disconnect( mPartHtmlWriter, SIGNAL( finished() ), this, SLOT( slotPrintMsg() ) ); + connect( mPartHtmlWriter, SIGNAL( finished() ), this, SLOT( slotPrintMsg() ) ); + setMessage( message, Viewer::Force ); +} + + +void ViewerPrivate::setMessageItem( const Akonadi::Item &item, Viewer::UpdateMode updateMode ) +{ + if ( mMessage && !NodeHelper::instance()->nodeProcessed( mMessage ) ) { + kWarning() << "The root node is not yet processed! Danger!"; + return; + } + + if ( mMessage && NodeHelper::instance()->nodeBeingProcessed( mMessage ) ) { + kWarning() << "The root node is not yet fully processed! Danger!"; + return; + } + + if ( mDeleteMessage ) { + kDebug() << "DELETE " << mMessage; + delete mMessage; + mMessage = 0; + } + NodeHelper::instance()->clear(); + mMimePartModel->setRoot( 0 ); + + mMessage = 0; //forget the old message if it was set + mMessageItem = item; + + if ( !mMessageItem.hasPayload() ) { + kWarning() << "Payload is not a MessagePtr!"; + return; + } + //Note: if I use MessagePtr for mMessage all over, I get a crash in the destructor + mMessage = new KMime::Message; + kDebug() << "START SHOWING" << mMessage; + + mMessage ->setContent( mMessageItem.payloadData() ); + mMessage ->parse(); + mDeleteMessage = true; + + + update( updateMode ); + kDebug() << "SHOWN" << mMessage; + +} + +void ViewerPrivate::setMessage(KMime::Message* aMsg, Viewer::UpdateMode updateMode, Viewer::Ownership ownerShip) +{ + if ( mDeleteMessage ) { + delete mMessage; + mMessage = 0; + } + NodeHelper::instance()->clear(); + mMimePartModel->setRoot( 0 ); + + if ( mPrinting ) + mLevelQuote = -1; + + // connect to the updates if we have hancy headers + + mMessage = aMsg; + mDeleteMessage = (ownerShip == Viewer::Transfer); + + if ( mMessage ) { + NodeHelper::instance()->setOverrideCodec( mMessage, overrideCodec() ); + } else { + mLastStatus.clear(); + } + + update( updateMode ); +} + +void ViewerPrivate::setMessagePart( KMime::Content * node ) +{ + htmlWriter()->reset(); + mColorBar->hide(); + htmlWriter()->begin( mCSSHelper->cssDefinitions( mUseFixedFont ) ); + htmlWriter()->write( mCSSHelper->htmlHead( mUseFixedFont ) ); + // end ### + if ( node ) { + MailViewerSource otpSource( this ); + ObjectTreeParser otp( &otpSource, 0, true ); + otp.parseObjectTree( node ); + } + // ### this, too + htmlWriter()->queue( "" ); + htmlWriter()->flush(); +} + + +void ViewerPrivate::setMessagePart( KMime::Content* aMsgPart, bool aHTML, + const QString& aFileName, const QString& pname ) +{ + // Cancel scheduled updates of the reader window, as that would stop the + // timer of the HTML writer, which would make viewing attachment not work + // anymore as not all HTML is written to the HTML part. + // We're updating the reader window here ourselves anyway. + mUpdateReaderWinTimer.stop(); + + KCursorSaver busy(KBusyPtr::busy()); + if ( aMsgPart->contentType()->mediaType() == "message" ) { + // if called from compose win + + KMime::Message* msg = new KMime::Message; + assert(aMsgPart!=0); + msg->setContent(aMsgPart->decodedContent()); + msg->parse(); + mMainWindow->setWindowTitle( msg->subject()->asUnicodeString() ); + setMessage( msg, Viewer::Force ); + mDeleteMessage = true; + } else if ( aMsgPart->contentType()->mediaType() == "text" ) { + if ( aMsgPart->contentType()->subType() == "x-vcard" || + aMsgPart->contentType()->subType() == "directory" ) { + showVCard( aMsgPart ); + return; + } + htmlWriter()->begin( mCSSHelper->cssDefinitions( mUseFixedFont ) ); + htmlWriter()->queue( mCSSHelper->htmlHead( mUseFixedFont ) ); + + if (aHTML && aMsgPart->contentType()->subType() == "html" ) { // HTML + // ### this is broken. It doesn't stip off the HTML header and footer! + htmlWriter()->queue( overrideCodec()? overrideCodec()->toUnicode(aMsgPart->decodedContent() ) : aMsgPart->decodedText() ); + mColorBar->setHtmlMode(); + } else { // plain text + const QByteArray str = aMsgPart->decodedContent(); + MailViewerSource otpSource( this ); + ObjectTreeParser otp( &otpSource ); + otp.writeBodyStr( str, + overrideCodec() ? overrideCodec() : NodeHelper::instance()->codec( aMsgPart ), + mMessage ? mMessage->from()->asUnicodeString() : QString() ); + } + htmlWriter()->queue(""); + htmlWriter()->flush(); + mMainWindow->setWindowTitle(i18n("View Attachment: %1", pname)); + } else if (aMsgPart->contentType()->mediaType() == "image" || + aMsgPart->contentType()->mimeType() == "application/postscript" ) + { + if (aFileName.isEmpty()) return; // prevent crash + // Open the window with a size so the image fits in (if possible): + QImageReader *iio = new QImageReader(); + iio->setFileName(aFileName); + if( iio->canRead() ) { + QImage img = iio->read(); + QRect desk = KGlobalSettings::desktopGeometry(mMainWindow); + // determine a reasonable window size + int width, height; + if( img.width() < 50 ) + width = 70; + else if( img.width()+20 < desk.width() ) + width = img.width()+20; + else + width = desk.width(); + if( img.height() < 50 ) + height = 70; + else if( img.height()+20 < desk.height() ) + height = img.height()+20; + else + height = desk.height(); + mMainWindow->resize( width, height ); + } + // Just write the img tag to HTML: + htmlWriter()->begin( mCSSHelper->cssDefinitions( mUseFixedFont ) ); + htmlWriter()->write( mCSSHelper->htmlHead( mUseFixedFont ) ); + htmlWriter()->write( "\n" + "\n" ); + htmlWriter()->end(); + q->setWindowTitle( i18n("View Attachment: %1", pname ) ); + q->show(); + delete iio; + } else { + htmlWriter()->begin( mCSSHelper->cssDefinitions( mUseFixedFont ) ); + htmlWriter()->queue( mCSSHelper->htmlHead( mUseFixedFont ) ); + htmlWriter()->queue( "
" );
+
+    QString str = aMsgPart->decodedText();
+    // A QString cannot handle binary data. So if it's shorter than the
+    // attachment, we assume the attachment is binary:
+    if( str.length() < aMsgPart->decodedContent().size() ) {
+      str.prepend( i18np("[KMail: Attachment contains binary data. Trying to show first character.]",
+          "[KMail: Attachment contains binary data. Trying to show first %1 characters.]",
+                               str.length()) + QChar::fromLatin1('\n') );
+    }
+    htmlWriter()->queue( Qt::escape( str ) );
+    htmlWriter()->queue( "
" ); + htmlWriter()->queue(""); + htmlWriter()->flush(); + mMainWindow->setWindowTitle(i18n("View Attachment: %1", pname)); + } +} + + +void ViewerPrivate::showHideMimeTree( ) +{ + if ( GlobalSettings::self()->mimeTreeMode() == GlobalSettings::EnumMimeTreeMode::Always ) + mMimePartTree->show(); + else { + // don't rely on QSplitter maintaining sizes for hidden widgets: + KConfigGroup reader( Global::instance()->config() , "Reader" ); + saveSplitterSizes( reader ); + mMimePartTree->hide(); + } + if ( mToggleMimePartTreeAction && ( mToggleMimePartTreeAction->isChecked() != mMimePartTree->isVisible() ) ) + mToggleMimePartTreeAction->setChecked( mMimePartTree->isVisible() ); +} + + +void ViewerPrivate::atmViewMsg(KMime::Content* aMsgPart) +{ + assert(aMsgPart!=0); + KMime::Content* msg = new KMime::Content( mMessage->parent() ); + msg->setContent(aMsgPart->decodedContent()); + msg->parse(); + assert(msg != 0); +/*FIXME(Andras) port it + msg->setMsgSerNum( 0 ); // because lookups will fail + // some information that is needed for imap messages with LOD + msg->setParent( message()->parent() ); + msg->setUID(message()->UID()); + msg->setReadyToShow(true); + + KMReaderMainWin *win = new KMReaderMainWin(); + win->showMsg( overrideEncoding(), msg ); + win->show(); + */ +} + +void ViewerPrivate::adjustLayout() { + if ( GlobalSettings::self()->mimeTreeLocation() == GlobalSettings::EnumMimeTreeLocation::bottom ) + mSplitter->addWidget( mMimePartTree ); + else + mSplitter->insertWidget( 0, mMimePartTree ); + mSplitter->setSizes( mSplitterSizes ); + + if ( GlobalSettings::self()->mimeTreeMode() == GlobalSettings::EnumMimeTreeMode::Always && + mMsgDisplay ) + mMimePartTree->show(); + else + mMimePartTree->hide(); + + if ( GlobalSettings::self()->showColorBar() && mMsgDisplay ) + mColorBar->show(); + else + mColorBar->hide(); +} + + +void ViewerPrivate::saveSplitterSizes( KConfigGroup & c ) const +{ + if ( !mSplitter || !mMimePartTree ) + return; + if ( mMimePartTree->isHidden() ) + return; // don't rely on QSplitter maintaining sizes for hidden widgets. + + const bool mimeTreeAtBottom = GlobalSettings::self()->mimeTreeLocation() == GlobalSettings::EnumMimeTreeLocation::bottom; + c.writeEntry( "MimePaneHeight", mSplitter->sizes()[ mimeTreeAtBottom ? 1 : 0 ] ); + c.writeEntry( "MessagePaneHeight", mSplitter->sizes()[ mimeTreeAtBottom ? 0 : 1 ] ); +} + +void ViewerPrivate::createWidgets() { + QVBoxLayout * vlay = new QVBoxLayout( q ); + vlay->setMargin( 0 ); + mSplitter = new QSplitter( Qt::Vertical, q ); + mSplitter->setObjectName( "mSplitter" ); + mSplitter->setChildrenCollapsible( false ); + vlay->addWidget( mSplitter ); + mMimePartTree = new QTreeView( mSplitter ); + mMimePartTree->setObjectName( "mMimePartTree" ); + mMimePartModel = new MimeTreeModel( mMimePartTree ); + mMimePartTree->setModel( mMimePartModel ); + mMimePartTree->setSelectionMode( QAbstractItemView::ExtendedSelection ); + mMimePartTree->setSelectionBehavior( QAbstractItemView::SelectRows ); + connect(mMimePartTree, SIGNAL( activated( const QModelIndex& ) ), this, SLOT( slotMimePartSelected( const QModelIndex& ) ) ); + mMimePartTree->setContextMenuPolicy(Qt::CustomContextMenu); + connect(mMimePartTree, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( slotMimeTreeContextMenuRequested(const QPoint&)) ); + mBox = new KHBox( mSplitter ); + setStyleDependantFrameWidth(); + mBox->setFrameStyle( mMimePartTree->frameStyle() ); + mColorBar = new HtmlStatusBar( mBox ); + mColorBar->setObjectName( "mColorBar" ); + mViewer = new KHTMLPart( mBox ); + mViewer->setObjectName( "mViewer" ); + // Remove the shortcut for the selectAll action from khtml part. It's redefined to + // CTRL-SHIFT-A in kmail and clashes with kmails CTRL-A action. + KAction *selectAll = qobject_cast( + mViewer->actionCollection()->action( "selectAll" ) ); + if ( selectAll ) { + selectAll->setShortcut( KShortcut() ); + } else { + kDebug() << "Failed to find khtml's selectAll action to remove it's shortcut"; + } + mSplitter->setStretchFactor( mSplitter->indexOf(mMimePartTree), 0 ); + mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); +} + + +void ViewerPrivate::createActions() +{ + KActionCollection *ac = mActionCollection; + if ( !ac ) { + return; + } + + KToggleAction *raction = 0; + + // header style + KActionMenu *headerMenu = new KActionMenu(i18nc("View->", "&Headers"), this); + ac->addAction("view_headers", headerMenu ); + headerMenu->setHelpText( i18n("Choose display style of message headers") ); + + connect( headerMenu, SIGNAL(triggered(bool)), + this, SLOT(slotCycleHeaderStyles()) ); + + QActionGroup *group = new QActionGroup( this ); + raction = new KToggleAction( i18nc("View->headers->", "&Enterprise Headers"), this); + ac->addAction( "view_headers_enterprise", raction ); + connect( raction, SIGNAL(triggered(bool)), SLOT(slotEnterpriseHeaders()) ); + raction->setHelpText( i18n("Show the list of headers in Enterprise style") ); + group->addAction( raction ); + headerMenu->addAction( raction ); + + raction = new KToggleAction(i18nc("View->headers->", "&Fancy Headers"), this); + ac->addAction("view_headers_fancy", raction ); + connect(raction, SIGNAL(triggered(bool) ), SLOT(slotFancyHeaders())); + raction->setHelpText( i18n("Show the list of headers in a fancy format") ); + group->addAction( raction ); + headerMenu->addAction( raction ); + + raction = new KToggleAction(i18nc("View->headers->", "&Brief Headers"), this); + ac->addAction("view_headers_brief", raction ); + connect(raction, SIGNAL(triggered(bool) ), SLOT(slotBriefHeaders())); + raction->setHelpText( i18n("Show brief list of message headers") ); + group->addAction( raction ); + headerMenu->addAction( raction ); + + raction = new KToggleAction(i18nc("View->headers->", "&Standard Headers"), this); + ac->addAction("view_headers_standard", raction ); + connect(raction, SIGNAL(triggered(bool) ), SLOT(slotStandardHeaders())); + raction->setHelpText( i18n("Show standard list of message headers") ); + group->addAction( raction ); + headerMenu->addAction( raction ); + + raction = new KToggleAction(i18nc("View->headers->", "&Long Headers"), this); + ac->addAction("view_headers_long", raction ); + connect(raction, SIGNAL(triggered(bool) ), SLOT(slotLongHeaders())); + raction->setHelpText( i18n("Show long list of message headers") ); + group->addAction( raction ); + headerMenu->addAction( raction ); + + raction = new KToggleAction(i18nc("View->headers->", "&All Headers"), this); + ac->addAction("view_headers_all", raction ); + connect(raction, SIGNAL(triggered(bool) ), SLOT(slotAllHeaders())); + raction->setHelpText( i18n("Show all message headers") ); + group->addAction( raction ); + headerMenu->addAction( raction ); + + // attachment style + KActionMenu *attachmentMenu = new KActionMenu(i18nc("View->", "&Attachments"), this); + ac->addAction("view_attachments", attachmentMenu ); + attachmentMenu->setHelpText( i18n("Choose display style of attachments") ); + connect( attachmentMenu, SIGNAL(triggered(bool)), + this, SLOT(slotCycleAttachmentStrategy()) ); + + group = new QActionGroup( this ); + raction = new KToggleAction(i18nc("View->attachments->", "&As Icons"), this); + ac->addAction("view_attachments_as_icons", raction ); + connect(raction, SIGNAL(triggered(bool) ), SLOT(slotIconicAttachments())); + raction->setHelpText( i18n("Show all attachments as icons. Click to see them.") ); + group->addAction( raction ); + attachmentMenu->addAction( raction ); + + raction = new KToggleAction(i18nc("View->attachments->", "&Smart"), this); + ac->addAction("view_attachments_smart", raction ); + connect(raction, SIGNAL(triggered(bool) ), SLOT(slotSmartAttachments())); + raction->setHelpText( i18n("Show attachments as suggested by sender.") ); + group->addAction( raction ); + attachmentMenu->addAction( raction ); + + raction = new KToggleAction(i18nc("View->attachments->", "&Inline"), this); + ac->addAction("view_attachments_inline", raction ); + connect(raction, SIGNAL(triggered(bool) ), SLOT(slotInlineAttachments())); + raction->setHelpText( i18n("Show all attachments inline (if possible)") ); + group->addAction( raction ); + attachmentMenu->addAction( raction ); + + raction = new KToggleAction(i18nc("View->attachments->", "&Hide"), this); + ac->addAction("view_attachments_hide", raction ); + connect(raction, SIGNAL(triggered(bool) ), SLOT(slotHideAttachments())); + raction->setHelpText( i18n("Do not show attachments in the message viewer") ); + group->addAction( raction ); + attachmentMenu->addAction( raction ); + + // Set Encoding submenu + mSelectEncodingAction = new KSelectAction(KIcon("character-set"), i18n("&Set Encoding"), this); + mSelectEncodingAction->setToolBarMode( KSelectAction::MenuMode ); + ac->addAction("encoding", mSelectEncodingAction ); + connect(mSelectEncodingAction,SIGNAL( triggered(int)), + SLOT( slotSetEncoding() )); + QStringList encodings = ViewerPrivate::supportedEncodings( false ); + encodings.prepend( i18n( "Auto" ) ); + mSelectEncodingAction->setItems( encodings ); + mSelectEncodingAction->setCurrentItem( 0 ); + + // + // Message Menu + // + + // copy selected text to clipboard + mCopyAction = ac->addAction( KStandardAction::Copy, "kmail_copy", this, + SLOT(slotCopySelectedText()) ); + + // copy all text to clipboard + mSelectAllAction = new KAction(i18n("Select All Text"), this); + ac->addAction("mark_all_text", mSelectAllAction ); + connect(mSelectAllAction, SIGNAL(triggered(bool) ), SLOT(selectAll())); + mSelectAllAction->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_A)); + + // copy Email address to clipboard + mCopyURLAction = new KAction( KIcon( "edit-copy" ), + i18n( "Copy Link Address" ), this ); + ac->addAction( "copy_url", mCopyURLAction ); + connect( mCopyURLAction, SIGNAL(triggered(bool)), SLOT(slotUrlCopy()) ); + + // open URL + mUrlOpenAction = new KAction( KIcon( "document-open" ), i18n( "Open URL" ), this ); + ac->addAction( "open_url", mUrlOpenAction ); + connect( mUrlOpenAction, SIGNAL(triggered(bool)), this, SLOT(slotUrlOpen()) ); + + // use fixed font + mToggleFixFontAction = new KToggleAction( i18n( "Use Fi&xed Font" ), this ); + ac->addAction( "toggle_fixedfont", mToggleFixFontAction ); + connect( mToggleFixFontAction, SIGNAL(triggered(bool)), SLOT(slotToggleFixedFont()) ); + mToggleFixFontAction->setShortcut( QKeySequence( Qt::Key_X ) ); + + // Show message structure viewer + mToggleMimePartTreeAction = new KToggleAction( i18n( "Show Message Structure" ), this ); + ac->addAction( "toggle_mimeparttree", mToggleMimePartTreeAction ); + connect( mToggleMimePartTreeAction, SIGNAL(toggled(bool)), + SLOT(slotToggleMimePartTree())); + + mViewSourceAction = new KAction(i18n("&View Source"), this); + ac->addAction("view_source", mViewSourceAction ); + connect(mViewSourceAction, SIGNAL(triggered(bool) ), SLOT(slotShowMessageSource())); + mViewSourceAction->setShortcut(QKeySequence(Qt::Key_V)); + + mSaveMessageAction = new KAction(i18n("&Save message"), this); + ac->addAction("save_message", mSaveMessageAction); + connect(mSaveMessageAction, SIGNAL(triggered(bool) ), SLOT(slotSaveMessage())); + mSaveMessageAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S)); + + // + // Scroll actions + // + mScrollUpAction = new KAction( i18n("Scroll Message Up"), this ); + mScrollUpAction->setShortcut( QKeySequence( Qt::Key_Up ) ); + ac->addAction( "scroll_up", mScrollUpAction ); + connect( mScrollUpAction, SIGNAL( triggered( bool ) ), + q, SLOT( slotScrollUp() ) ); + + mScrollDownAction = new KAction( i18n("Scroll Message Down"), this ); + mScrollDownAction->setShortcut( QKeySequence( Qt::Key_Down ) ); + ac->addAction( "scroll_down", mScrollDownAction ); + connect( mScrollDownAction, SIGNAL( triggered( bool ) ), + q, SLOT( slotScrollDown() ) ); + + mScrollUpMoreAction = new KAction( i18n("Scroll Message Up (More)"), this ); + mScrollUpMoreAction->setShortcut( QKeySequence( Qt::Key_PageUp ) ); + ac->addAction( "scroll_up_more", mScrollUpMoreAction ); + connect( mScrollUpMoreAction, SIGNAL( triggered( bool ) ), + q, SLOT( slotScrollPrior() ) ); + + mScrollDownMoreAction = new KAction( i18n("Scroll Message Down (More)"), this ); + mScrollDownMoreAction->setShortcut( QKeySequence( Qt::Key_PageDown ) ); + ac->addAction( "scroll_down_more", mScrollDownMoreAction ); + connect( mScrollDownMoreAction, SIGNAL( triggered( bool ) ), + q, SLOT( slotScrollNext() ) ); +} + + +void ViewerPrivate::showContextMenu( KMime::Content* content, const QPoint &pos ) +{ + if ( !content ) + return; + const bool isAttachment = !content->contentType()->isMultipart() && !content->isTopLevel(); + const bool isRoot = (content == mMessage); + + KMenu popup; + + if ( !isRoot ) { + popup.addAction( SmallIcon( "document-save-as" ), i18n( "Save &As..." ), + this, SLOT( slotAttachmentSaveAs() ) ); + + if ( isAttachment ) { + popup.addAction( SmallIcon( "document-open" ), i18nc( "to open", "Open" ), + this, SLOT( slotAttachmentOpen() ) ); + popup.addAction( i18n( "Open With..." ), this, SLOT( slotAttachmentOpenWith() ) ); + popup.addAction( i18nc( "to view something", "View" ), this, SLOT( slotAttachmentView() ) ); + } + } + + /* + * FIXME make optional? + popup.addAction( i18n( "Save as &Encoded..." ), this, + SLOT( slotSaveAsEncoded() ) ); + */ + + popup.addAction( i18n( "Save All Attachments..." ), this, + SLOT( slotAttachmentSaveAll() ) ); + + // edit + delete only for attachments + if ( !isRoot ) { + if ( isAttachment ) { + popup.addAction( SmallIcon( "edit-copy" ), i18n( "Copy" ), + this, SLOT( slotAttachmentCopy() ) ); + if ( GlobalSettings::self()->allowAttachmentDeletion() ) + popup.addAction( SmallIcon( "edit-delete" ), i18n( "Delete Attachment" ), + this, SLOT( slotAttachmentDelete() ) ); + if ( GlobalSettings::self()->allowAttachmentEditing() ) + popup.addAction( SmallIcon( "document-properties" ), i18n( "Edit Attachment" ), + this, SLOT( slotAttachmentEdit() ) ); + } + + if ( !content->isTopLevel() ) + popup.addAction( i18n( "Properties" ), this, SLOT( slotAttachmentProperties() ) ); + } + popup.exec( mMimePartTree->viewport()->mapToGlobal( pos ) ); + +} + + +KToggleAction *ViewerPrivate::actionForHeaderStyle( const HeaderStyle * style, const HeaderStrategy * strategy ) { + if ( !mActionCollection ) + return 0; + const char * actionName = 0; + if ( style == HeaderStyle::enterprise() ) + actionName = "view_headers_enterprise"; + if ( style == HeaderStyle::fancy() ) + actionName = "view_headers_fancy"; + else if ( style == HeaderStyle::brief() ) + actionName = "view_headers_brief"; + else if ( style == HeaderStyle::plain() ) { + if ( strategy == HeaderStrategy::standard() ) + actionName = "view_headers_standard"; + else if ( strategy == HeaderStrategy::rich() ) + actionName = "view_headers_long"; + else if ( strategy == HeaderStrategy::all() ) + actionName = "view_headers_all"; + } + if ( actionName ) + return static_cast(mActionCollection->action(actionName)); + else + return 0; +} + +KToggleAction *ViewerPrivate::actionForAttachmentStrategy( const AttachmentStrategy * as ) { + if ( !mActionCollection ) + return 0; + const char * actionName = 0; + if ( as == AttachmentStrategy::iconic() ) + actionName = "view_attachments_as_icons"; + else if ( as == AttachmentStrategy::smart() ) + actionName = "view_attachments_smart"; + else if ( as == AttachmentStrategy::inlined() ) + actionName = "view_attachments_inline"; + else if ( as == AttachmentStrategy::hidden() ) + actionName = "view_attachments_hide"; + + if ( actionName ) + return static_cast(mActionCollection->action(actionName)); + else + return 0; +} + + +void ViewerPrivate::readGlobalOverrideCodec() +{ + // if the global character encoding wasn't changed then there's nothing to do + if ( GlobalSettings::self()->overrideCharacterEncoding() == mOldGlobalOverrideEncoding ) + return; + + setOverrideEncoding( GlobalSettings::self()->overrideCharacterEncoding() ); + mOldGlobalOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding(); +} + + +const QTextCodec * ViewerPrivate::overrideCodec() const +{ + if ( mOverrideEncoding.isEmpty() || mOverrideEncoding == "Auto" ) // Auto + return 0; + else + return ViewerPrivate::codecForName( mOverrideEncoding.toLatin1() ); +} + + +static QColor nextColor( const QColor & c ) +{ + int h, s, v; + c.getHsv( &h, &s, &v ); + return QColor::fromHsv( (h + 50) % 360, qMax(s, 64), v ); +} + +QString ViewerPrivate::renderAttachments(KMime::Content * node, const QColor &bgColor ) +{ + + if ( !node ) + return QString(); + + QString html; + KMime::Content * child = NodeHelper::firstChild( node ); + + if ( child) { + QString subHtml = renderAttachments( child, nextColor( bgColor ) ); + if ( !subHtml.isEmpty() ) { + + QString visibility; + if( !mShowAttachmentQuicklist ) { + visibility.append( "display:none;" ); + } + + QString margin; + if ( node != mMessage || headerStyle() != HeaderStyle::enterprise() ) + margin = "padding:2px; margin:2px; "; + QString align = "left"; + if ( headerStyle() == HeaderStyle::enterprise() ) + align = "right"; + if ( node->contentType()->mediaType() == "message" || node == mMessage ) + html += QString::fromLatin1("
").arg( bgColor.name() ).arg( margin ) + .arg( align ).arg( visibility ); + html += subHtml; + if ( node->contentType()->mediaType() == "message" || node == mMessage ) + html += "
"; + } + } else { + QString label, icon; + icon = NodeHelper::instance()->iconName( node, KIconLoader::Small ); + label = node->contentDescription()->asUnicodeString(); + if( label.isEmpty() ) { + label = NodeHelper::fileName( node ); + } + + bool typeBlacklisted = node->contentType()->mediaType() == "multipart"; + if ( !typeBlacklisted ) { + typeBlacklisted = StringUtil::isCryptoPart( node->contentType()->mediaType(), node->contentType()->subType(), + node->contentDisposition()->filename() ); + } + typeBlacklisted = typeBlacklisted || node == mMessage; + if ( !label.isEmpty() && !icon.isEmpty() && !typeBlacklisted ) { + html += "
"; + html += QString::fromLatin1( "" ).arg( bgColor.name() ); + QString fileName = NodeHelper::instance()->writeNodeToTempFile( node ); + QString href = NodeHelper::asHREF( node, "header" ); + html += QString::fromLatin1( "" ); + html += " "; + if ( headerStyle() == HeaderStyle::enterprise() ) { + QFont bodyFont = mCSSHelper->bodyFont( mUseFixedFont ); + QFontMetrics fm( bodyFont ); + html += fm.elidedText( label, Qt::ElideRight, 180 ); + } else { + html += label; + } + html += "
"; + } + } + + KMime::Content *next = NodeHelper::nextSibling( node ); + if ( next ) + html += renderAttachments( next, nextColor ( bgColor ) ); + + return html; +} + +KMime::Content* ViewerPrivate::findContentByType(KMime::Content *content, const QByteArray &type) +{ + KMime::Content::List list = content->contents(); + Q_FOREACH(KMime::Content *c, list) + { + if (c->contentType()->mimeType() == type) + return c; + } + return 0L; + +} + + +QString ViewerPrivate::fixEncoding( const QString &encoding ) +{ + QString returnEncoding = encoding; + // According to http://www.iana.org/assignments/character-sets, uppercase is + // preferred in MIME headers + if ( returnEncoding.toUpper().contains( "ISO " ) ) { + returnEncoding = returnEncoding.toUpper(); + returnEncoding.replace( "ISO ", "ISO-" ); + } + return returnEncoding; +} + +//----------------------------------------------------------------------------- +QString ViewerPrivate::encodingForName( const QString &descriptiveName ) +{ + QString encoding = KGlobal::charsets()->encodingForName( descriptiveName ); + return ViewerPrivate::fixEncoding( encoding ); +} + +//----------------------------------------------------------------------------- +const QTextCodec* ViewerPrivate::codecForName(const QByteArray& _str) +{ + if (_str.isEmpty()) + return 0; + QByteArray codec = _str; + kAsciiToLower(codec.data()); + return KGlobal::charsets()->codecForName(codec); +} + +QStringList ViewerPrivate::supportedEncodings(bool usAscii) +{ + QStringList encodingNames = KGlobal::charsets()->availableEncodingNames(); + QStringList encodings; + QMap mimeNames; + for (QStringList::Iterator it = encodingNames.begin(); + it != encodingNames.end(); ++it) + { + QTextCodec *codec = KGlobal::charsets()->codecForName(*it); + QString mimeName = (codec) ? QString(codec->name()).toLower() : (*it); + if (!mimeNames.contains(mimeName) ) + { + encodings.append( KGlobal::charsets()->descriptionForEncoding(*it) ); + mimeNames.insert( mimeName, true ); + } + } + encodings.sort(); + if (usAscii) + encodings.prepend(KGlobal::charsets()->descriptionForEncoding("us-ascii") ); + return encodings; +} + + +void ViewerPrivate::update( Viewer::UpdateMode updateMode ) +{ + // Avoid flicker, somewhat of a cludge + if ( updateMode == Viewer::Force ) { + // stop the timer to avoid calling updateReaderWin twice + mUpdateReaderWinTimer.stop(); + updateReaderWin(); + } + else if (mUpdateReaderWinTimer.isActive()) { + mUpdateReaderWinTimer.setInterval( delay ); + } else { + mUpdateReaderWinTimer.start( 0 ); + } +} + + +void ViewerPrivate::slotUrlOpen( const KUrl &url ) +{ + kDebug() << "slotUrlOpen " << url; + if ( !url.isEmpty() ) { + mUrlClicked = url; + slotUrlOpen( url, KParts::OpenUrlArguments(), KParts::BrowserArguments() ); + } +} + + +void ViewerPrivate::slotUrlOpen(const KUrl &aUrl, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &) +{ + mUrlClicked = aUrl; + + if ( URLHandlerManager::instance()->handleClick( aUrl, this ) ) + return; + + kWarning() << "Unhandled URL click! " << aUrl; + emit urlClicked( aUrl, Qt::LeftButton ); +} + + +void ViewerPrivate::slotUrlOn(const QString &aUrl) +{ + const KUrl url(aUrl); + if ( url.protocol() == "kmail" || url.protocol() == "x-kmail" + || (url.protocol().isEmpty() && url.path().isEmpty()) ) { + mViewer->setDNDEnabled( false ); + } else { + mViewer->setDNDEnabled( true ); + } + + if ( aUrl.trimmed().isEmpty() ) { + KPIM::BroadcastStatus::instance()->reset(); + return; + } + + mUrlClicked = url; + + const QString msg = URLHandlerManager::instance()->statusBarMessage( url, this ); + + kWarning( msg.isEmpty(), 5006 ) << "Unhandled URL hover!"; + KPIM::BroadcastStatus::instance()->setTransientStatusMsg( msg ); +} + +void ViewerPrivate::slotUrlPopup(const QString &aUrl, const QPoint& aPos) +{ + const KUrl url( aUrl ); + mUrlClicked = url; + + if ( URLHandlerManager::instance()->handleContextMenuRequest( url, aPos, this ) ) + return; + + if ( mMessage ) { + kWarning() << "Unhandled URL right-click!"; + emit popupMenu( *mMessage, url, aPos ); + } +} + +void ViewerPrivate::slotFind() +{ + mViewer->findText(); +} + + +void ViewerPrivate::slotToggleFixedFont() +{ + mUseFixedFont = !mUseFixedFont; + saveRelativePosition(); + update( Viewer::Force ); +} + +void ViewerPrivate::slotToggleMimePartTree() +{ + if ( mToggleMimePartTreeAction->isChecked() ) + GlobalSettings::self()->setMimeTreeMode( GlobalSettings::EnumMimeTreeMode::Always ); + else + GlobalSettings::self()->setMimeTreeMode( GlobalSettings::EnumMimeTreeMode::Never ); + showHideMimeTree(); +} + + +void ViewerPrivate::slotShowMessageSource() +{ + QString str = QString::fromAscii( mMessage->encodedContent() ); + + MailSourceViewer *viewer = new MailSourceViewer(); // deletes itself upon close + viewer->setWindowTitle( i18n("Message as Plain Text") ); + viewer->setText( str ); + if( mUseFixedFont ) { + viewer->setFont( KGlobalSettings::fixedFont() ); + } + + // Well, there is no widget to be seen here, so we have to use QCursor::pos() + // Update: (GS) I'm not going to make this code behave according to Xinerama + // configuration because this is quite the hack. + if ( QApplication::desktop()->isVirtualDesktop() ) { + int scnum = QApplication::desktop()->screenNumber( QCursor::pos() ); + viewer->resize( QApplication::desktop()->screenGeometry( scnum ).width()/2, + 2 * QApplication::desktop()->screenGeometry( scnum ).height()/3); + } else { + viewer->resize( QApplication::desktop()->geometry().width()/2, + 2 * QApplication::desktop()->geometry().height()/3); + } + viewer->show(); +} + +void ViewerPrivate::updateReaderWin() +{ + if ( !mMsgDisplay ) { + return; + } + + mViewer->setOnlyLocalReferences( !htmlLoadExternal() ); + + htmlWriter()->reset(); + //TODO: if the item doesn't have the payload fetched, try to fetch it? Maybe not here, but in setMessageItem. + if ( mMessage ) + { + if ( GlobalSettings::self()->showColorBar() ) { + mColorBar->show(); + } else { + mColorBar->hide(); + } + displayMessage(); + } else { + mColorBar->hide(); + mMimePartTree->hide(); + //FIXME(Andras) mMimePartTree->clearAndResetSortOrder(); + htmlWriter()->begin( mCSSHelper->cssDefinitions( mUseFixedFont) ); + htmlWriter()->write( mCSSHelper->htmlHead( mUseFixedFont ) + "" ); + htmlWriter()->end(); + } + + if ( mSavedRelativePosition ) { + QScrollArea *scrollview = mViewer->view(); + scrollview->widget()->move( 0, + qRound( scrollview->widget()->size().height() * mSavedRelativePosition ) ); + mSavedRelativePosition = 0; + } +} + + +void ViewerPrivate::slotMimePartSelected( const QModelIndex &index ) +{ + KMime::Content *content = static_cast( index.internalPointer() ); + if ( !mMimePartModel->parent(index).isValid() && index.row() == 0 ) { + update(Viewer::Force); + } else + setMessagePart( content ); +} + + +void ViewerPrivate::slotCycleHeaderStyles() { + const HeaderStrategy * strategy = headerStrategy(); + const HeaderStyle * style = headerStyle(); + + const char * actionName = 0; + if ( style == HeaderStyle::enterprise() ) { + slotFancyHeaders(); + actionName = "view_headers_fancy"; + } + if ( style == HeaderStyle::fancy() ) { + slotBriefHeaders(); + actionName = "view_headers_brief"; + } else if ( style == HeaderStyle::brief() ) { + slotStandardHeaders(); + actionName = "view_headers_standard"; + } else if ( style == HeaderStyle::plain() ) { + if ( strategy == HeaderStrategy::standard() ) { + slotLongHeaders(); + actionName = "view_headers_long"; + } else if ( strategy == HeaderStrategy::rich() ) { + slotAllHeaders(); + actionName = "view_headers_all"; + } else if ( strategy == HeaderStrategy::all() ) { + slotEnterpriseHeaders(); + actionName = "view_headers_enterprise"; + } + } + + if ( actionName ) + static_cast( mActionCollection->action( actionName ) )->setChecked( true ); +} + + +void ViewerPrivate::slotBriefHeaders() +{ + setHeaderStyleAndStrategy( HeaderStyle::brief(), + HeaderStrategy::brief() ); + if( !mExternalWindow ) + writeConfig(); +} + + +void ViewerPrivate::slotFancyHeaders() +{ + setHeaderStyleAndStrategy( HeaderStyle::fancy(), + HeaderStrategy::rich() ); + if( !mExternalWindow ) + writeConfig(); +} + + +void ViewerPrivate::slotEnterpriseHeaders() +{ + setHeaderStyleAndStrategy( HeaderStyle::enterprise(), + HeaderStrategy::rich() ); + if( !mExternalWindow ) + writeConfig(); +} + + +void ViewerPrivate::slotStandardHeaders() +{ + setHeaderStyleAndStrategy( HeaderStyle::plain(), + HeaderStrategy::standard()); + writeConfig(); +} + + +void ViewerPrivate::slotLongHeaders() +{ + setHeaderStyleAndStrategy( HeaderStyle::plain(), + HeaderStrategy::rich() ); + if( !mExternalWindow ) + writeConfig(); +} + + + +void ViewerPrivate::slotAllHeaders() { + setHeaderStyleAndStrategy( HeaderStyle::plain(), + HeaderStrategy::all() ); + if( !mExternalWindow ) + writeConfig(); +} + + +void ViewerPrivate::slotCycleAttachmentStrategy() +{ + setAttachmentStrategy( attachmentStrategy()->next() ); + KToggleAction * action = actionForAttachmentStrategy( attachmentStrategy() ); + assert( action ); + action->setChecked( true ); +} + + +void ViewerPrivate::slotIconicAttachments() +{ + setAttachmentStrategy( AttachmentStrategy::iconic() ); +} + + +void ViewerPrivate::slotSmartAttachments() +{ + setAttachmentStrategy( AttachmentStrategy::smart() ); +} + + +void ViewerPrivate::slotInlineAttachments() +{ + setAttachmentStrategy( AttachmentStrategy::inlined() ); +} + + +void ViewerPrivate::slotHideAttachments() +{ + setAttachmentStrategy( AttachmentStrategy::hidden() ); +} + + +void ViewerPrivate::slotAtmView( KMime::Content *atmNode ) +{ + if ( atmNode ) { + QString fileName = NodeHelper::instance()->tempFileUrlFromNode( atmNode ).toLocalFile(); + + QString pname = NodeHelper::fileName( atmNode ); + if (pname.isEmpty()) pname = atmNode->contentDescription()->asUnicodeString(); + if (pname.isEmpty()) pname = "unnamed"; + // image Attachment is saved already + if (kasciistricmp(atmNode->contentType()->mediaType(), "message")==0) { + atmViewMsg( atmNode ); + } else if ((kasciistricmp(atmNode->contentType()->mediaType(), "text")==0) && + ( (kasciistricmp(atmNode->contentType()->subType(), "x-vcard")==0) || + (kasciistricmp(atmNode->contentType()->subType(), "directory")==0) )) { + setMessagePart( atmNode, htmlMail(), fileName, pname ); + } else { + /*TODO(Andras) port + KMReaderMainWin *win = new KMReaderMainWin(&msgPart, htmlMail(), + name, pname, overrideEncoding() ); + win->show(); + */ + } + } +} + + +void ViewerPrivate::slotDelayedResize() +{ + mSplitter->setGeometry( 0, 0, q->width(), q->height() ); +} + + +void ViewerPrivate::slotPrintMsg() +{ + disconnect( mPartHtmlWriter, SIGNAL( finished() ), this, SLOT( slotPrintMsg() ) ); + if ( !mMessage ) return; + mViewer->view()->print(); +} + + +void ViewerPrivate::slotSetEncoding() +{ + if ( mSelectEncodingAction->currentItem() == 0 ) // Auto + mOverrideEncoding.clear(); + else + mOverrideEncoding = ViewerPrivate::encodingForName( mSelectEncodingAction->currentText() ); + update( Viewer::Force ); +} + +void ViewerPrivate::injectAttachments() +{ + // inject attachments in header view + // we have to do that after the otp has run so we also see encrypted parts + DOM::Document doc = mViewer->htmlDocument(); + DOM::Element injectionPoint = doc.getElementById( "attachmentInjectionPoint" ); + if ( injectionPoint.isNull() ) + return; + + QString imgpath( KStandardDirs::locate("data","kmail/pics/") ); + QString visibility; + QString urlHandle; + QString imgSrc; + if( !mShowAttachmentQuicklist ) { + urlHandle.append( "kmail:showAttachmentQuicklist" ); + imgSrc.append( "quicklistClosed.png" ); + } else { + urlHandle.append( "kmail:hideAttachmentQuicklist" ); + imgSrc.append( "quicklistOpened.png" ); + } + + QColor background = KColorScheme( QPalette::Active, KColorScheme::View ).background().color(); + QString html = renderAttachments( mMessage, background ); + if ( html.isEmpty() ) + return; + + QString link(""); + if ( headerStyle() == HeaderStyle::fancy() ) { + link += "
"; + html.prepend( link ); + html.prepend( QString::fromLatin1("
%1 
" ).arg(i18n("Attachments:")) ); + } else { + link += "
"; + html.prepend( link ); + } + + assert( injectionPoint.tagName() == "div" ); + static_cast( injectionPoint ).setInnerHTML( html ); +} + + +void ViewerPrivate::slotSettingsChanged() +{ + mShowColorbar = GlobalSettings::self()->showColorBar(); + saveRelativePosition(); + update( Viewer::Force ); +} + + +void ViewerPrivate::slotMimeTreeContextMenuRequested( const QPoint& pos ) +{ + QModelIndex index = mMimePartTree->indexAt( pos ); + if ( index.isValid() ) { + KMime::Content *content = static_cast( index.internalPointer() ); + showContextMenu( content, pos ); + } +} + +void ViewerPrivate::slotAttachmentOpenWith() +{ + QItemSelectionModel *selectionModel = mMimePartTree->selectionModel(); + QModelIndexList selectedRows = selectionModel->selectedRows(); + + Q_FOREACH(QModelIndex index, selectedRows) + { + KMime::Content *content = static_cast( index.internalPointer() ); + attachmentOpenWith( content ); + } +} + +void ViewerPrivate::slotAttachmentOpen() +{ + + QItemSelectionModel *selectionModel = mMimePartTree->selectionModel(); + QModelIndexList selectedRows = selectionModel->selectedRows(); + + Q_FOREACH(QModelIndex index, selectedRows) + { + KMime::Content *content = static_cast( index.internalPointer() ); + attachmentOpen( content ); + } +} + + +void ViewerPrivate::slotAttachmentSaveAs() +{ + KMime::Content::List contents = selectedContents(); + + if ( contents.isEmpty() ) + return; + + saveAttachments( contents ); +} + + +void ViewerPrivate::slotAttachmentSaveAll() +{ + KMime::Content::List contents = allContents( mMessage ); + + for ( KMime::Content::List::iterator it = contents.begin(); + it != contents.end(); ) { + // only body parts which have a filename or a name parameter (except for + // the root node for which name is set to the message's subject) are + // considered attachments + KMime::Content* content = *it; + if ( content->contentDisposition()->filename().trimmed().isEmpty() && + ( content->contentType()->name().trimmed().isEmpty() || + content == mMessage ) ) { + KMime::Content::List::iterator delIt = it; + ++it; + contents.erase( delIt ); + } else { + ++it; + } + } + + if ( contents.isEmpty() ) { + KMessageBox::information( mMainWindow, i18n("Found no attachments to save.") ); + return; + } + + saveAttachments( contents ); + +} + + +void ViewerPrivate::slotAttachmentView() +{ + KMime::Content::List contents = selectedContents(); + + Q_FOREACH(KMime::Content *content, contents) + { + slotAtmView( content ); + } + +} + +void ViewerPrivate::slotAttachmentProperties() +{ + KMime::Content::List contents = selectedContents(); + + if ( contents.isEmpty() ) + return; + + Q_FOREACH( KMime::Content *content, contents ) { + KPIM::AttachmentPropertiesDialog *dialog = new KPIM::AttachmentPropertiesDialog( content, mMainWindow ); + dialog->setAttribute( Qt::WA_DeleteOnClose ); + dialog->show(); + } +} + + +void ViewerPrivate::slotAttachmentCopy() +{ + KMime::Content::List contents = selectedContents(); + + if ( contents.isEmpty() ) + return; + + QList urls; + Q_FOREACH( KMime::Content *content, contents) { + KUrl kUrl = NodeHelper::instance()->writeNodeToTempFile( content ); + QUrl url = QUrl::fromPercentEncoding( kUrl.toEncoded() ); + if ( !url.isValid() ) + continue; + urls.append( url ); + } + + if ( urls.isEmpty() ) + return; + + QMimeData *mimeData = new QMimeData; + mimeData->setUrls( urls ); + QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard ); +} + + +void ViewerPrivate::slotAttachmentDelete() +{ + KMime::Content::List contents = selectedContents(); + if ( contents.isEmpty() ) + return; + + bool showWarning = true; + Q_FOREACH( KMime::Content *content, contents ) { + if ( !deleteAttachment( content, showWarning ) ) + return; + showWarning = false; + } +} + + +void ViewerPrivate::slotAttachmentEdit() +{ + KMime::Content::List contents = selectedContents(); + if ( contents.isEmpty() ) + return; + + bool showWarning = true; + Q_FOREACH( KMime::Content *content, contents ) { + if ( !editAttachment( content, showWarning ) ) + return; + showWarning = false; + } +} + + +void ViewerPrivate::slotAttachmentEditDone( MessageViewer::EditorWatcher* editorWatcher ) +{ + QString name = editorWatcher->url().fileName(); + if ( editorWatcher->fileChanged() ) { + QFile file( name ); + if ( file.open( QIODevice::ReadOnly ) ) { + QByteArray data = file.readAll(); + KMime::Content *node = mEditorWatchers[editorWatcher]; + node->setBody( data ); + file.close(); + + mMessageItem.setPayloadFromData( mMessage->encodedContent() ); + Akonadi::ItemModifyJob *job = new Akonadi::ItemModifyJob( mMessageItem ); + } + } + mEditorWatchers.remove( editorWatcher ); + QFile::remove( name ); +} + +void ViewerPrivate::slotLevelQuote( int l ) +{ + kDebug() << "Old Level:" << mLevelQuote << "New Level:" << l; + + mLevelQuote = l; + saveRelativePosition(); + update( Viewer::Force ); +} + + +void ViewerPrivate::slotHandleAttachment( int choice ) +{ + /*FIXME(Andras) port to akonadi + mAtmUpdate = true; + partNode* node = mRootNode ? mRootNode->findId( mAtmCurrent ) : 0; + if ( choice == KMHandleAttachmentCommand::Delete ) { + slotDeleteAttachment( node ); + } else if ( choice == KMHandleAttachmentCommand::Edit ) { + slotEditAttachment( node ); + } else if ( choice == KMHandleAttachmentCommand::Copy ) { + if ( !node ) + return; + QList urls; + KUrl kUrl = tempFileUrlFromPartNode( node ); + QUrl url = QUrl::fromPercentEncoding( kUrl.toEncoded() ); + + if ( !url.isValid() ) + return; + urls.append( url ); + + QMimeData *mimeData = new QMimeData; + mimeData->setUrls( urls ); + QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard ); + } else if ( choice == KMHandleAttachmentCommand::ScrollTo ) { + scrollToAttachment( node ); + } + else { + KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand( + node, message(), mAtmCurrent, mAtmCurrentName, + KMHandleAttachmentCommand::AttachmentAction( choice ), KService::Ptr( 0 ), this ); + connect( command, SIGNAL( showAttachment( int, const QString& ) ), + this, SLOT( slotAtmView( int, const QString& ) ) ); + command->start(); + } + */ +} + +void ViewerPrivate::slotCopySelectedText() +{ + QString selection = mViewer->selectedText(); + selection.replace( QChar::Nbsp, ' ' ); + QApplication::clipboard()->setText( selection ); +} + +void ViewerPrivate::selectAll() +{ + mViewer->selectAll(); +} + +void ViewerPrivate::slotUrlClicked() +{ + kDebug() << "Clicked on " << mUrlClicked; + /*FIXME Andras + KMMainWidget *mainWidget = dynamic_cast(mMainWindow); + uint identity = 0; + if ( message() && message()->parent() ) { + identity = message()->parent()->identity(); + } + + KMCommand *command = new KMUrlClickedCommand( mUrlClicked, identity, this, + false, mainWidget ); + command->start();*/ +} + + +void ViewerPrivate::slotUrlCopy() +{ + // we don't necessarily need a mainWidget for KMUrlCopyCommand so + // it doesn't matter if the dynamic_cast fails. + /* FIXME(Andras) port it + KMCommand *command = + new KMUrlCopyCommand( mUrlClicked, + dynamic_cast( mMainWindow ) ); + command->start(); + */ +} + + +void ViewerPrivate::slotUrlSave() +{ + /*FIXME(Andras) port to akonadi + KMCommand *command = new KMUrlSaveCommand( mUrlClicked, mMainWindow ); + command->start(); + */ +} + +void ViewerPrivate::slotSaveMessage() +{ + KUrl url = KFileDialog::getSaveUrl( KUrl::fromPath( mMessage->subject()->asUnicodeString().trimmed() + .replace( QDir::separator(), '_' ) ), + "*.mbox", mMainWindow ); + + if ( url.isEmpty() ) + return; + + QByteArray data( mMessage->encodedContent() ); + QDataStream ds; + QFile file; + KTemporaryFile tf; + if ( url.isLocalFile() ) + { + // save directly + file.setFileName( url.toLocalFile() ); + if ( !file.open( QIODevice::WriteOnly ) ) + { + KMessageBox::error( mMainWindow, + i18nc( "1 = file name, 2 = error string", + "Could not write to the file
%1

%2", + file.fileName(), + QString::fromLocal8Bit( strerror( errno ) ) ), + i18n( "Error saving attachment" ) ); + return; + } + + //TODO handle huge attachment (and on demand attachment loading), especially saving them to + //remote destination + +/*FIXME(Andras) port it + // #79685 by default use the umask the user defined, but let it be configurable + if ( GlobalSettings::self()->disregardUmask() ) + fchmod( file.handle(), S_IRUSR | S_IWUSR ); +*/ + ds.setDevice( &file ); + } else + { + // tmp file for upload + tf.open(); + ds.setDevice( &tf ); + } + + if ( ds.writeRawData( data.data(), data.size() ) == -1) + { + QFile *f = static_cast( ds.device() ); + KMessageBox::error( mMainWindow, + i18nc( "1 = file name, 2 = error string", + "Could not write to the file
%1

%2", + f->fileName(), + f->errorString() ), + i18n( "Error saving attachment" ) ); + return; + } + + if ( !url.isLocalFile() ) + { + // QTemporaryFile::fileName() is only defined while the file is open + QString tfName = tf.fileName(); + tf.close(); + if ( !KIO::NetAccess::upload( tfName, url, mMainWindow ) ) + { + KMessageBox::error( mMainWindow, + i18nc( "1 = file name, 2 = error string", + "Could not write to the file
%1

%2", + url.prettyUrl(), + KIO::NetAccess::lastErrorString() ), + i18n( "Error saving attachment" ) ); + return; + } + } else + file.close(); + return; +} + + +void ViewerPrivate::saveRelativePosition() +{ + const QScrollArea *scrollview = mViewer->view(); + mSavedRelativePosition = static_cast( scrollview->widget()->pos().y() ) / + scrollview->widget()->size().height(); +} + +//TODO(Andras) inline them +bool ViewerPrivate::htmlMail() const +{ + return ((mHtmlMail && !mHtmlOverride) || (!mHtmlMail && mHtmlOverride)); +} + +bool ViewerPrivate::htmlLoadExternal() const +{ + return ((mHtmlLoadExternal && !mHtmlLoadExtOverride) || + (!mHtmlLoadExternal && mHtmlLoadExtOverride)); +} + +void ViewerPrivate::setHtmlOverride( bool override ) +{ + mHtmlOverride = override; +} + +bool ViewerPrivate::htmlOverride() const +{ + return mHtmlOverride; +} + +void ViewerPrivate::setHtmlLoadExtOverride( bool override ) +{ + mHtmlLoadExtOverride = override; +} + +bool ViewerPrivate::htmlLoadExtOverride() const +{ + return mHtmlLoadExtOverride; +} + +void ViewerPrivate::setDecryptMessageOverwrite( bool overwrite ) +{ + mDecrytMessageOverwrite = overwrite; +} + +bool ViewerPrivate::showSignatureDetails() const +{ + return mShowSignatureDetails; +} + +void ViewerPrivate::setShowSignatureDetails( bool showDetails ) +{ + mShowSignatureDetails = showDetails; +} + +bool ViewerPrivate::showAttachmentQuicklist() const +{ + return mShowAttachmentQuicklist; +} + +void ViewerPrivate::setShowAttachmentQuicklist( bool showAttachmentQuicklist ) +{ + mShowAttachmentQuicklist = showAttachmentQuicklist; +} + +void ViewerPrivate::scrollToAttachment( const KMime::Content *node ) +{ + DOM::Document doc = mViewer->htmlDocument(); + + // The anchors for this are created in ObjectTreeParser::parseObjectTree() + mViewer->gotoAnchor( QString::fromLatin1( "att%1" ).arg( node->index().toString() ) ); + + // Remove any old color markings which might be there + const KMime::Content *root = node->topLevel(); + int totalChildCount = allContents( root ).size(); + for ( int i = 0; i <= totalChildCount + 1; i++ ) { + DOM::Element attachmentDiv = doc.getElementById( QString( "attachmentDiv%1" ).arg( i + 1 ) ); + if ( !attachmentDiv.isNull() ) + attachmentDiv.removeAttribute( "style" ); + } + + // Now, color the div of the attachment in yellow, so that the user sees what happened. + // We created a special marked div for this in writeAttachmentMarkHeader() in ObjectTreeParser, + // find and modify that now. + + + kDebug() << "'ANDRIS::looking for " << QString( "attachmentDiv%1" ).arg( node->index().toString() ); + DOM::Element attachmentDiv = doc.getElementById( QString( "attachmentDiv%1" ).arg( node->index().toString() ) ); + if ( attachmentDiv.isNull() ) { + kWarning() << "Could not find attachment div for attachment" << node->index().toString(); + return; + } + attachmentDiv.setAttribute( "style", QString( "border:2px solid %1" ) + .arg( cssHelper()->pgpWarnColor().name() ) ); + + // Update rendering, otherwise the rendering is not updated when the user clicks on an attachment + // that causes scrolling and the open attachment dialog + doc.updateRendering(); + q->update(); +} + +void ViewerPrivate::setUseFixedFont( bool useFixedFont ) +{ + mUseFixedFont = useFixedFont; + if ( mToggleFixFontAction ) + { + mToggleFixFontAction->setChecked( mUseFixedFont ); + } +} + +// Checks if the given node has a parent node that is a DIV which has an ID attribute +// with the value specified here +bool ViewerPrivate::hasParentDivWithId( const DOM::Node &start, const QString &id ) +{ + if ( start.isNull() ) + return false; + + if ( start.nodeName().string() == "div" ) { + for ( unsigned int i = 0; i < start.attributes().length(); i++ ) { + if ( start.attributes().item( i ).nodeName().string() == "id" && + start.attributes().item( i ).nodeValue().string() == id ) + return true; + } + } + + if ( !start.parentNode().isNull() ) + return hasParentDivWithId( start.parentNode(), id ); + else return false; +} + +#include "viewer_p.moc" diff -Nru /tmp/ydgLOpdYuA/kde-nightly-kdepim-20091006+svn1032120/messageviewer/viewer_p.h /tmp/897jxOC6qO/kde-nightly-kdepim-20091009+svn1033340/messageviewer/viewer_p.h --- kde-nightly-kdepim-20091006+svn1032120/messageviewer/viewer_p.h 1970-01-01 01:00:00.000000000 +0100 +++ kde-nightly-kdepim-20091009+svn1033340/messageviewer/viewer_p.h 2009-10-09 23:31:07.000000000 +0100 @@ -0,0 +1,540 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + Copyright (c) 1997 Markus Wuebben + Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Copyright (c) 2009 Andras Mantia + + 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) any later version. + + 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. +*/ + +#ifndef MAILVIEWER_P_H +#define MAILVIEWER_P_H + +#include + +#include +#include +#include + +#include + +#include + +#include + +#include + +#include "viewer.h" //not so nice, it is actually for the enums from MailViewer + +using KPIM::MessageStatus; + +class KAction; +class KActionCollection; +class KSelectAction; +class KToggleAction; +class KHBox; +class KHTMLPart; + +class QPoint; +class QSplitter; +class QStyle; +class QModelIndex; +class QTreeView; + +class MimeTreeModel; +class ConfigureWidget; + +class KHtmlPartHtmlWriter; +class HtmlStatusBar; + +namespace KParts { + struct BrowserArguments; + class OpenUrlArguments; +} + +namespace MessageViewer { + + namespace Interface { + class BodyPartMemento; + } + class EditorWatcher; + class HtmlWriter; + class CSSHelper; + class AttachmentStrategy; + class ObjectTreeParser; + class HeaderStrategy; + class HeaderStyle; +} + +namespace MessageViewer { +/** Private class for MailViewer. +* @author andras@kdab.net +*/ +class ViewerPrivate : public QObject { + Q_OBJECT +public: + + ViewerPrivate(Viewer *aParent, + KSharedConfigPtr config, + QWidget *mainWindow, + KActionCollection* actionCollection); + + virtual ~ViewerPrivate(); + + /** Returns message part from given URL or null if invalid. */ + KMime::Content* nodeFromUrl(const KUrl &url); + + /** Returns the message part for a given content index. */ + KMime::Content* nodeForContentIndex( const KMime::ContentIndex& index ); + + /** Open the attachment pointed to the node. + * @param fileName - if not empty, use this file to load the attachment content + */ + void openAttachment( KMime::Content *node, const QString & fileName ); + + /** Delete the attachment the @param node points to. Returns false if the user + cancelled the deletion, true in all other cases (including failure to delete + the attachment!) */ + bool deleteAttachment( KMime::Content* node, bool showWarning = true ); + + /** Edit the attachment the @param node points to. Returns false if the user + cancelled the editing, true in all other cases! */ + bool editAttachment( KMime::Content* node, bool showWarning = true ); + + void emitUrlClicked( const KUrl & url, int button ) { + emit urlClicked( url, button ); + } + + void emitPopupMenu( const KUrl & url, const QPoint & p ) { + if ( mMessage ) + emit popupMenu( *mMessage, url, p ); + } + + /** Access to the KHTMLPart used for the viewer. Use with + care! */ + KHTMLPart *htmlPart() const { return mViewer; } + + void showAttachmentPopup( int id, const QString & name, const QPoint & p ); + + /** retrieve BodyPartMemento of id \a which for partNode \a node */ + Interface::BodyPartMemento * bodyPartMemento( const KMime::Content * node, const QByteArray & which ) const; + + /** set/replace BodyPartMemento \a memento of id \a which for + partNode \a node. If there was a BodyPartMemento registered + already, replaces (deletes) that one. */ + void setBodyPartMemento( const KMime::Content * node, const QByteArray & which, Interface::BodyPartMemento * memento ); + + /** deletes all BodyPartMementos. Use this when skipping to another + message (as opposed to re-loading the same one again). */ + void clearBodyPartMementos(); + + /** + * Sets the current attachment ID and the current attachment temporary filename + * to the given values. + * Call this so that slotHandleAttachment() knows which attachment to handle. + */ + void prepareHandleAttachment( int id, const QString& fileName ); + + + /** This function returns the complete data that were in this + * message parts - *after* all encryption has been removed that + * could be removed. + * - This is used to store the message in decrypted form. + */ + void objectTreeToDecryptedMsg( KMime::Content* node, + QByteArray& resultingData, + KMime::Message& theMessage, + bool weAreReplacingTheRootNode = false, + int recCount = 0 ); + + QString createAtmFileLink( const QString& atmFileName ) const; + KService::Ptr getServiceOffer( KMime::Content *content); + bool saveContent( KMime::Content* content, const KUrl& url, bool encoded ); + void saveAttachments( const KMime::Content::List & contents ); + KMime::Content::List allContents( const KMime::Content * content ); + KMime::Content::List selectedContents(); + void attachmentOpenWith( KMime::Content *node ); + void attachmentOpen( KMime::Content *node ); + + + /** Return the HtmlWriter connected to the KHTMLPart we use */ + HtmlWriter * htmlWriter() { return mHtmlWriter; } + + CSSHelper* cssHelper() const; + + /** Returns whether the message should be decryted. */ + bool decryptMessage() const; + + /** Set the width of the frame to a reasonable value for the current GUI + style */ + void setStyleDependantFrameWidth(); + + /** Calculate the pixel size */ + int pointsToPixel(int pointSize) const; + + /** Display a generic HTML splash page instead of a message. + * @param info - the text to be displayed in HTML format + */ + void displaySplashPage( const QString &info ); + + /** Enable the displaying of messages again after an splash (or other) page was displayed */ + void enableMessageDisplay(); + + /** Feeds the HTML viewer with the contents of the given message. + HTML begin/end parts are written around the message. */ + void displayMessage(); + + /** Parse the root message and add it's contents to the reader window. */ + void parseMsg(); + + /** Creates a nice mail header depending on the current selected + header style. */ + QString writeMsgHeader( KMime::Message* aMsg, KMime::Content* vCardNode = 0, bool topLevel = false ); + + /** show window containing information about a vCard. */ + void showVCard(KMime::Content *msgPart); + + /** HTML initialization. */ + virtual void initHtmlWidget(void); + + /** Event filter */ + bool eventFilter( QObject *obj, QEvent *ev ); + + /** Read settings from app's config file. */ + void readConfig(); + + /** Write settings to app's config file. Calls sync() if withSync is true. */ + void writeConfig( bool withSync=true ) const; + + /** Get the message header style. */ + const HeaderStyle * headerStyle() const { + return mHeaderStyle; + } + + /** Set the header style and strategy. We only want them to be set + together. */ + void setHeaderStyleAndStrategy( const HeaderStyle * style, + const HeaderStrategy * strategy ); + + /** Get the message header strategy. */ + const HeaderStrategy * headerStrategy() const { + return mHeaderStrategy; + } + + /** Get/set the message attachment strategy. */ + const AttachmentStrategy * attachmentStrategy() const { + return mAttachmentStrategy; + } + void setAttachmentStrategy( const AttachmentStrategy * strategy ); + + /** Get selected override character encoding. + @return The encoding selected by the user or an empty string if auto-detection + is selected. */ + QString overrideEncoding() const { return mOverrideEncoding; } + + /** Set the override character encoding. */ + void setOverrideEncoding( const QString & encoding ); + + void setPrintFont( const QFont& font ); + + /** Set printing mode */ + virtual void setPrinting(bool enable) { mPrinting = enable; } + + + /** Print message. */ + void printMessage( KMime::Message* message ); + + + /** Set the Akonadi item that will be displayed. + * @param item - the Akonadi item to be displayed. If it doesn't hold a mail (KMime::Message::Ptr as payload data), + * an empty page is shown. + * @param updateMode - update the display immediately or not. See MailViewer::UpdateMode. + */ + void setMessageItem(const Akonadi::Item& item, Viewer::UpdateMode updateMode = Viewer::Delayed ); + + + /** Set the message that shall be shown. + * @param msg - the message to be shown. If 0, an empty page is displayed. + * @param updateMode - update the display immediately or not. See MailViewer::UpdateMode. + * @param MailViewer::Ownership - Transfer means the ownership of the msg pointer is taken by the lib + */ + void setMessage(KMime::Message* msg, Viewer::UpdateMode updateMode = Viewer::Delayed, Viewer::Ownership = Viewer::Keep); + + /** Instead of settings a message to be shown sets a message part + to be shown */ + void setMessagePart( KMime::Content* aMsgPart, bool aHTML, + const QString& aFileName, const QString& pname ); + + void setMessagePart( KMime::Content * node ); + + /** Show or hide the Mime Tree Viewer if configuration + is set to smart mode. */ + void showHideMimeTree(); + + /** View message part of type message/RFC822 in extra viewer window. */ + void atmViewMsg(KMime::Content* msgPart); + + void adjustLayout(); + void saveSplitterSizes( KConfigGroup & c ) const; + void createWidgets(); + void createActions(); + + void showContextMenu( KMime::Content* content, const QPoint& point); + + KToggleAction * actionForHeaderStyle( const HeaderStyle *, + const HeaderStrategy * ); + KToggleAction * actionForAttachmentStrategy( const AttachmentStrategy * ); + /** Read override codec from configuration */ + void readGlobalOverrideCodec(); + + /** Get codec corresponding to the currently selected override character encoding. + @return The override codec or 0 if auto-detection is selected. */ + const QTextCodec * overrideCodec() const; + + + QString renderAttachments( KMime::Content *node, const QColor &bgColor ); + + KMime::Content* findContentByType(KMime::Content *content, const QByteArray &type); //TODO(Andras) move to NodeHelper + /** + * Fixes an encoding received by a KDE function and returns the proper, + * MIME-compilant encoding name instead. + * @see encodingForName + */ + static QString fixEncoding( const QString &encoding ); //TODO(Andras) move to a utility class? + + /** + * Drop-in replacement for KCharsets::encodingForName(). The problem with + * the KCharsets function is that it returns "human-readable" encoding names + * like "ISO 8859-15" instead of valid encoding names like "ISO-8859-15". + * This function fixes this by replacing whitespace with a hyphen. + */ + static QString encodingForName( const QString &descriptiveName ); //TODO(Andras) move to a utility class? + + /** Return a QTextCodec for the specified charset. + * This function is a bit more tolerant, than QTextCodec::codecForName */ + static const QTextCodec* codecForName(const QByteArray& _str); //TODO(Andras) move to a utility class? + /** + * Return a list of the supported encodings + * @param usAscii if true, US-Ascii encoding will be prepended to the list. + */ + static QStringList supportedEncodings( bool usAscii ); //TODO(Andras) move to a utility class? + + /** Saves the relative position of the scroll view. Call this before calling update() + if you want to preserve the current view. */ + void saveRelativePosition(); + + bool htmlMail() const; + bool htmlLoadExternal() const; + + /** Return selected text */ + QString copyText(); + + /** Get the html override setting */ + bool htmlOverride() const; + + /** Override default html mail setting */ + void setHtmlOverride( bool override ); + + /** Get the load external references override setting */ + bool htmlLoadExtOverride() const; + +/** Override default load external references setting */ + void setHtmlLoadExtOverride( bool override ); + + /** Enforce message decryption. */ + void setDecryptMessageOverwrite( bool overwrite = true ); + + /** Show signature details. */ + bool showSignatureDetails() const; + + /** Show signature details. */ + void setShowSignatureDetails( bool showDetails = true ) ; + + /* show or hide the list that points to the attachments */ + bool showAttachmentQuicklist() const; + + /* show or hide the list that points to the attachments */ + void setShowAttachmentQuicklist( bool showAttachmentQuicklist = true ); + + void emitNoDrag() {emit noDrag(); } + + void scrollToAttachment( const KMime::Content *node ); + void setUseFixedFont( bool useFixedFont ); + +public slots: + + void slotUrlOpen( const KUrl &url = KUrl() ); + + /** An URL has been activate with a click. */ + void slotUrlOpen(const KUrl &url, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &); + + /** The mouse has moved on or off an URL. */ + void slotUrlOn(const QString &url); + + /** The user presses the right mouse button on an URL. */ + void slotUrlPopup(const QString &, const QPoint& mousePos); + + /** The user selected "Find" from the menu. */ + void slotFind(); + + /** The user toggled the "Fixed Font" flag from the view menu. */ + void slotToggleFixedFont(); + void slotToggleMimePartTree(); + + /** Show the message source */ + void slotShowMessageSource(); + + /** Refresh the reader window */ + void updateReaderWin(); + + void slotMimePartSelected( const QModelIndex &index ); + + void slotCycleHeaderStyles(); + void slotBriefHeaders(); + void slotFancyHeaders(); + void slotEnterpriseHeaders(); + void slotStandardHeaders(); + void slotLongHeaders(); + void slotAllHeaders(); + + void slotCycleAttachmentStrategy(); + void slotIconicAttachments(); + void slotSmartAttachments(); + void slotInlineAttachments(); + void slotHideAttachments(); + + /** Some attachment operations. */ + void slotAtmView( KMime::Content *atmNode ); + void slotDelayedResize(); + + /** Print message. Called on as a response of finished() signal of mPartHtmlWriter + after rendering is finished. + In the very end it deletes the KMReaderWin window that was created + for the purpose of rendering. */ + void slotPrintMsg(); + + void slotSetEncoding(); + void injectAttachments(); + void slotSettingsChanged(); + void slotMimeTreeContextMenuRequested( const QPoint& pos ); + void slotAttachmentOpenWith(); + void slotAttachmentOpen(); + void slotAttachmentSaveAs(); + void slotAttachmentSaveAll(); + void slotAttachmentView(); + void slotAttachmentProperties(); + void slotAttachmentCopy(); + void slotAttachmentDelete(); + void slotAttachmentEdit(); + void slotAttachmentEditDone(MessageViewer::EditorWatcher* editorWatcher); + void slotLevelQuote( int l ); + + /** + * Does an action for the current attachment. + * The action is defined by the KMHandleAttachmentCommand::AttachmentAction + * enum. + * prepareHandleAttachment() needs to be called before calling this to set the + * correct attachment ID. + */ + void slotHandleAttachment( int action ); + /** Copy the selected text to the clipboard */ + void slotCopySelectedText(); + + /** Select message body. */ + void selectAll(); + + void slotUrlClicked(); + /** Copy URL in mUrlCurrent to clipboard. Removes "mailto:" at + beginning of URL before copying. */ + void slotUrlCopy(); + /** Save the page to a file */ + void slotUrlSave(); + void slotSaveMessage(); + /** Re-parse the current message. */ + void update(MessageViewer::Viewer::UpdateMode updateMode = Viewer::Delayed); + + bool hasParentDivWithId( const DOM::Node &start, const QString &id ); + +signals: + void replaceMsgByUnencryptedVersion(); + void popupMenu(KMime::Message &msg, const KUrl &url, const QPoint& mousePos); + void urlClicked(const KUrl &url, int button); + void noDrag(); + +public: + bool mHtmlMail, mHtmlLoadExternal, mHtmlOverride, mHtmlLoadExtOverride; + KMime::Message *mMessage; //the current message, if it was set manually + Akonadi::Item mMessageItem; //the message item from Akonadi + bool mDeleteMessage; //the message was created in the lib, eg. by calling setMessageItem() + // widgets: + QSplitter * mSplitter; + KHBox *mBox; + HtmlStatusBar *mColorBar; + QTreeView* mMimePartTree; //FIXME(Andras) port the functionality from KMMimePartTree to a new view class or to here with signals/slots + MimeTreeModel *mMimePartModel; + KHTMLPart *mViewer; + + const AttachmentStrategy * mAttachmentStrategy; + const HeaderStrategy * mHeaderStrategy; + const HeaderStyle * mHeaderStyle; + /** where did the user save the attachment last time */ + QString mSaveAttachDir; + static const int delay; + QTimer mUpdateReaderWinTimer; + QTimer mResizeTimer; + QString mOverrideEncoding; + QString mOldGlobalOverrideEncoding; // used to detect changes of the global override character encoding + bool mMsgDisplay; + bool mNoMDNsWhenEncrypted; + MessageStatus mLastStatus; + + CSSHelper * mCSSHelper; + bool mUseFixedFont; + bool mPrinting; + bool mShowColorbar; + //bool mShowCompleteMessage; + int mMimeTreeMode; + bool mMimeTreeAtBottom; + QList mSplitterSizes; + QString mIdOfLastViewedMessage; + QWidget *mMainWindow; + KActionCollection *mActionCollection; + KAction *mCopyAction, *mCopyURLAction, + *mUrlOpenAction, *mSelectAllAction, + *mScrollUpAction, *mScrollDownAction, *mScrollUpMoreAction, *mScrollDownMoreAction, *mViewSourceAction, *mSaveMessageAction; + KSelectAction *mSelectEncodingAction; + KToggleAction *mToggleFixFontAction; + KToggleAction *mToggleMimePartTreeAction; + KUrl mUrlClicked; + HtmlWriter * mHtmlWriter; + /** Used only to be able to connect and disconnect finished() signal + in printMsg() and slotPrintMsg() since mHtmlWriter points only to abstract non-QObject class. */ + QPointer mPartHtmlWriter; + QMap mBodyPartMementoMap; + + int mChoice; + float mSavedRelativePosition; + int mLevelQuote; + bool mDecrytMessageOverwrite; + bool mShowSignatureDetails; + bool mShowAttachmentQuicklist; + bool mExternalWindow; + QMap mEditorWatchers; + + Viewer *const q; +}; + +} + +#endif