kmail

urlhandlermanager.cpp

00001 /*  -*- c++ -*-
00002     urlhandlermanager.cpp
00003 
00004     This file is part of KMail, the KDE mail client.
00005     Copyright (c) 2002-2003 Klar�vdalens Datakonsult AB
00006     Copyright (c) 2003      Marc Mutz <mutz@kde.org>
00007 
00008     KMail is free software; you can redistribute it and/or modify it
00009     under the terms of the GNU General Public License, version 2, as
00010     published by the Free Software Foundation.
00011 
00012     KMail is distributed in the hope that it will be useful, but
00013     WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021     In addition, as a special exception, the copyright holders give
00022     permission to link the code of this program with any edition of
00023     the Qt library by Trolltech AS, Norway (or with modified versions
00024     of Qt that use the same license as Qt), and distribute linked
00025     combinations including the two.  You must obey the GNU General
00026     Public License in all respects for all of the code used other than
00027     Qt.  If you modify this file, you may extend this exception to
00028     your version of the file, but you are not obligated to do so.  If
00029     you do not wish to do so, delete this exception statement from
00030     your version.
00031 */
00032 
00033 #ifdef HAVE_CONFIG_H
00034 #include <config.h>
00035 #endif
00036 
00037 #include "urlhandlermanager.h"
00038 
00039 #include "interfaces/urlhandler.h"
00040 #include "interfaces/bodyparturlhandler.h"
00041 #include "partNode.h"
00042 #include "partnodebodypart.h"
00043 #include "kmreaderwin.h"
00044 #include "kmkernel.h"
00045 #include "callback.h"
00046 
00047 #include <kimproxy.h>
00048 #include "stl_util.h"
00049 #include <kurl.h>
00050 
00051 #include <algorithm>
00052 using std::for_each;
00053 using std::remove;
00054 using std::find;
00055 
00056 KMail::URLHandlerManager * KMail::URLHandlerManager::self = 0;
00057 
00058 namespace {
00059   class ShowHtmlSwitchURLHandler : public KMail::URLHandler {
00060   public:
00061     ShowHtmlSwitchURLHandler() : KMail::URLHandler() {}
00062     ~ShowHtmlSwitchURLHandler() {}
00063 
00064     bool handleClick( const KURL &, KMReaderWin * ) const;
00065     bool handleContextMenuRequest( const KURL &, const QPoint &, KMReaderWin * ) const {
00066       return false;
00067     }
00068     QString statusBarMessage( const KURL &, KMReaderWin * ) const;
00069   };
00070 
00071   class ExpandCollapseQuoteURLManager : public KMail::URLHandler {
00072   public:
00073     ExpandCollapseQuoteURLManager() : KMail::URLHandler() {}
00074     ~ExpandCollapseQuoteURLManager() {}
00075 
00076     bool handleClick( const KURL &, KMReaderWin * ) const;
00077     bool handleContextMenuRequest( const KURL &, const QPoint &, KMReaderWin * ) const {
00078       return false;
00079     }
00080     QString statusBarMessage( const KURL &, KMReaderWin * ) const;
00081 
00082   };
00083 
00084   class SMimeURLHandler : public KMail::URLHandler {
00085   public:
00086     SMimeURLHandler() : KMail::URLHandler() {}
00087     ~SMimeURLHandler() {}
00088 
00089     bool handleClick( const KURL &, KMReaderWin * ) const;
00090     bool handleContextMenuRequest( const KURL &, const QPoint &, KMReaderWin * ) const {
00091       return false;
00092     }
00093     QString statusBarMessage( const KURL &, KMReaderWin * ) const;
00094   };
00095 
00096   class MailToURLHandler : public KMail::URLHandler {
00097   public:
00098     MailToURLHandler() : KMail::URLHandler() {}
00099     ~MailToURLHandler() {}
00100 
00101     bool handleClick( const KURL &, KMReaderWin * ) const { return false; }
00102     bool handleContextMenuRequest( const KURL &, const QPoint &, KMReaderWin * ) const {
00103       return false;
00104     }
00105     QString statusBarMessage( const KURL &, KMReaderWin * ) const;
00106   };
00107 
00108   class HtmlAnchorHandler : public KMail::URLHandler {
00109   public:
00110     HtmlAnchorHandler() : KMail::URLHandler() {}
00111     ~HtmlAnchorHandler() {}
00112 
00113     bool handleClick( const KURL &, KMReaderWin * ) const;
00114     bool handleContextMenuRequest( const KURL &, const QPoint &, KMReaderWin * ) const {
00115       return false;
00116     }
00117     QString statusBarMessage( const KURL &, KMReaderWin * ) const { return QString::null; }
00118   };
00119 
00120   class AttachmentURLHandler : public KMail::URLHandler {
00121   public:
00122     AttachmentURLHandler() : KMail::URLHandler() {}
00123     ~AttachmentURLHandler() {}
00124 
00125     bool handleClick( const KURL &, KMReaderWin * ) const;
00126     bool handleContextMenuRequest( const KURL &, const QPoint &, KMReaderWin * ) const;
00127     QString statusBarMessage( const KURL &, KMReaderWin * ) const;
00128   };
00129 
00130   class FallBackURLHandler : public KMail::URLHandler {
00131   public:
00132     FallBackURLHandler() : KMail::URLHandler() {}
00133     ~FallBackURLHandler() {}
00134 
00135     bool handleClick( const KURL &, KMReaderWin * ) const;
00136     bool handleContextMenuRequest( const KURL &, const QPoint &, KMReaderWin * ) const;
00137     QString statusBarMessage( const KURL & url, KMReaderWin * ) const {
00138       return url.prettyURL();
00139     }
00140   };
00141 
00142 } // anon namespace
00143 
00144 
00145 //
00146 //
00147 // BodyPartURLHandlerManager
00148 //
00149 //
00150 
00151 class KMail::URLHandlerManager::BodyPartURLHandlerManager : public KMail::URLHandler {
00152 public:
00153   BodyPartURLHandlerManager() : KMail::URLHandler() {}
00154   ~BodyPartURLHandlerManager();
00155 
00156   bool handleClick( const KURL &, KMReaderWin * ) const;
00157   bool handleContextMenuRequest( const KURL &, const QPoint &, KMReaderWin * ) const;
00158   QString statusBarMessage( const KURL &, KMReaderWin * ) const;
00159 
00160   void registerHandler( const Interface::BodyPartURLHandler * handler );
00161   void unregisterHandler( const Interface::BodyPartURLHandler * handler );
00162 
00163 private:
00164   typedef QValueVector<const Interface::BodyPartURLHandler*> BodyPartHandlerList;
00165   BodyPartHandlerList mHandlers;
00166 };
00167 
00168 KMail::URLHandlerManager::BodyPartURLHandlerManager::~BodyPartURLHandlerManager() {
00169   for_each( mHandlers.begin(), mHandlers.end(),
00170         DeleteAndSetToZero<Interface::BodyPartURLHandler>() );
00171 }
00172 
00173 void KMail::URLHandlerManager::BodyPartURLHandlerManager::registerHandler( const Interface::BodyPartURLHandler * handler ) {
00174   if ( !handler )
00175     return;
00176   unregisterHandler( handler ); // don't produce duplicates
00177   mHandlers.push_back( handler );
00178 }
00179 
00180 void KMail::URLHandlerManager::BodyPartURLHandlerManager::unregisterHandler( const Interface::BodyPartURLHandler * handler ) {
00181   // don't delete them, only remove them from the list!
00182   mHandlers.erase( remove( mHandlers.begin(), mHandlers.end(), handler ), mHandlers.end() );
00183 }
00184 
00185 static partNode * partNodeFromXKMailUrl( const KURL & url, KMReaderWin * w, QString * path ) {
00186   assert( path );
00187 
00188   if ( !w || url.protocol() != "x-kmail" )
00189     return 0;
00190   const QString urlPath = url.path();
00191 
00192   // urlPath format is: /bodypart/<random number>/<part id>/<path>
00193 
00194   kdDebug( 5006 ) << "BodyPartURLHandler: urlPath == \"" << urlPath << "\"" << endl;
00195   if ( !urlPath.startsWith( "/bodypart/" ) )
00196     return 0;
00197 
00198   const QStringList urlParts = QStringList::split( '/', urlPath.mid( 10 ), true );
00199   if ( urlParts.size() != 3 )
00200     return 0;
00201   bool ok = false;
00202   const int part_id = urlParts[1].toInt( &ok );
00203   if ( !ok )
00204     return 0;
00205   *path = KURL::decode_string( urlParts[2], 106 );
00206   return w->partNodeForId( part_id );
00207 }
00208 
00209 bool KMail::URLHandlerManager::BodyPartURLHandlerManager::handleClick( const KURL & url, KMReaderWin * w ) const {
00210   QString path;
00211   partNode * node = partNodeFromXKMailUrl( url, w, &path );
00212   if ( !node )
00213     return false;
00214   KMMessage *msg = w->message();
00215   if ( !msg ) return false;
00216   Callback callback( msg, w );
00217   KMail::PartNodeBodyPart part( *node, w->overrideCodec() );
00218   for ( BodyPartHandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it )
00219     if ( (*it)->handleClick( &part, path, callback ) )
00220       return true;
00221   return false;
00222 }
00223 
00224 bool KMail::URLHandlerManager::BodyPartURLHandlerManager::handleContextMenuRequest( const KURL & url, const QPoint & p, KMReaderWin * w ) const {
00225   QString path;
00226   partNode * node = partNodeFromXKMailUrl( url, w, &path );
00227   if ( !node )
00228     return false;
00229 
00230   KMail::PartNodeBodyPart part( *node, w->overrideCodec() );
00231   for ( BodyPartHandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it )
00232     if ( (*it)->handleContextMenuRequest( &part, path, p ) )
00233       return true;
00234   return false;
00235 }
00236 
00237 QString KMail::URLHandlerManager::BodyPartURLHandlerManager::statusBarMessage( const KURL & url, KMReaderWin * w ) const {
00238   QString path;
00239   partNode * node = partNodeFromXKMailUrl( url, w, &path );
00240   if ( !node )
00241     return QString::null;
00242 
00243   KMail::PartNodeBodyPart part( *node, w->overrideCodec() );
00244   for ( BodyPartHandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it ) {
00245     const QString msg = (*it)->statusBarMessage( &part, path );
00246     if ( !msg.isEmpty() )
00247       return msg;
00248   }
00249   return QString::null;
00250 }
00251 
00252 //
00253 //
00254 // URLHandlerManager
00255 //
00256 //
00257 
00258 KMail::URLHandlerManager::URLHandlerManager() {
00259   registerHandler( new ShowHtmlSwitchURLHandler() );
00260   registerHandler( new ExpandCollapseQuoteURLManager() );
00261   registerHandler( new SMimeURLHandler() );
00262   registerHandler( new MailToURLHandler() );
00263   registerHandler( new HtmlAnchorHandler() );
00264   registerHandler( new AttachmentURLHandler() );
00265   registerHandler( mBodyPartURLHandlerManager = new BodyPartURLHandlerManager() );
00266   registerHandler( new FallBackURLHandler() );
00267 }
00268 
00269 KMail::URLHandlerManager::~URLHandlerManager() {
00270   for_each( mHandlers.begin(), mHandlers.end(),
00271         DeleteAndSetToZero<URLHandler>() );
00272 }
00273 
00274 void KMail::URLHandlerManager::registerHandler( const URLHandler * handler ) {
00275   if ( !handler )
00276     return;
00277   unregisterHandler( handler ); // don't produce duplicates
00278   mHandlers.push_back( handler );
00279 }
00280 
00281 void KMail::URLHandlerManager::unregisterHandler( const URLHandler * handler ) {
00282   // don't delete them, only remove them from the list!
00283   mHandlers.erase( remove( mHandlers.begin(), mHandlers.end(), handler ), mHandlers.end() );
00284 }
00285 
00286 void KMail::URLHandlerManager::registerHandler( const Interface::BodyPartURLHandler * handler ) {
00287   if ( mBodyPartURLHandlerManager )
00288     mBodyPartURLHandlerManager->registerHandler( handler );
00289 }
00290 
00291 void KMail::URLHandlerManager::unregisterHandler( const Interface::BodyPartURLHandler * handler ) {
00292   if ( mBodyPartURLHandlerManager )
00293     mBodyPartURLHandlerManager->unregisterHandler( handler );
00294 }
00295 
00296 bool KMail::URLHandlerManager::handleClick( const KURL & url, KMReaderWin * w ) const {
00297   for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it )
00298     if ( (*it)->handleClick( url, w ) )
00299       return true;
00300   return false;
00301 }
00302 
00303 bool KMail::URLHandlerManager::handleContextMenuRequest( const KURL & url, const QPoint & p, KMReaderWin * w ) const {
00304   for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it )
00305     if ( (*it)->handleContextMenuRequest( url, p, w ) )
00306       return true;
00307   return false;
00308 }
00309 
00310 QString KMail::URLHandlerManager::statusBarMessage( const KURL & url, KMReaderWin * w ) const {
00311   for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it ) {
00312     const QString msg = (*it)->statusBarMessage( url, w );
00313     if ( !msg.isEmpty() )
00314       return msg;
00315   }
00316   return QString::null;
00317 }
00318 
00319 
00320 //
00321 //
00322 // URLHandler
00323 //
00324 //
00325 
00326 // these includes are temporary and should not be needed for the code
00327 // above this line, so they appear only here:
00328 #include "kmmessage.h"
00329 #include "kmreaderwin.h"
00330 #include "partNode.h"
00331 #include "kmmsgpart.h"
00332 
00333 #include <klocale.h>
00334 #include <kprocess.h>
00335 #include <kmessagebox.h>
00336 #include <khtml_part.h>
00337 
00338 #include <qstring.h>
00339 
00340 namespace {
00341   bool ShowHtmlSwitchURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
00342     if ( url.protocol() == "kmail" ) {
00343       if ( !w )
00344         return false;
00345 
00346       if ( url.path() == "showHTML" ) {
00347         w->setHtmlOverride( !w->htmlOverride() );
00348         w->update( true );
00349         return true;
00350       }
00351 
00352       if ( url.path() == "loadExternal" ) {
00353         w->setHtmlLoadExtOverride( !w->htmlLoadExtOverride() );
00354         w->update( true );
00355         return true;
00356       }
00357 
00358       if ( url.path() == "goOnline" ) {
00359         kmkernel->resumeNetworkJobs();
00360         return true;
00361       }
00362 
00363       if ( url.path() == "decryptMessage" ) {
00364         w->setDecryptMessageOverwrite( true );
00365         w->update( true );
00366         return true;
00367       }
00368 
00369       if ( url.path() == "showSignatureDetails" ) {
00370         w->setShowSignatureDetails();
00371         w->update( true );
00372         return true;
00373       }
00374       if ( url.path() == "hideSignatureDetails" ) {
00375         w->setShowSignatureDetails( false );
00376         w->update( true );
00377         return true;
00378       }
00379 
00380 //       if ( url.path() == "startIMApp" )
00381 //       {
00382 //         kmkernel->imProxy()->startPreferredApp();
00383 //         return true;
00384 //       }
00385 //       //FIXME: handle startIMApp urls in their own handler, or rename this one
00386     }
00387     return false;
00388   }
00389 
00390   QString ShowHtmlSwitchURLHandler::statusBarMessage( const KURL & url, KMReaderWin * ) const {
00391     if ( url.protocol() == "kmail" )
00392     {
00393       if ( url.path() == "showHTML" )
00394         return i18n("Turn on HTML rendering for this message.");
00395       if ( url.path() == "loadExternal" )
00396         return i18n("Load external references from the Internet for this message.");
00397       if ( url.path() == "goOnline" )
00398         return i18n("Work online");
00399     }
00400     return QString::null ;
00401   }
00402 }
00403 
00404 namespace {
00405 
00406   bool ExpandCollapseQuoteURLManager::handleClick(
00407       const KURL & url, KMReaderWin * w ) const
00408   {
00409     //  kmail:levelquote/?num      -> the level quote to collapse.
00410     //  kmail:levelquote/?-num      -> expand all levels quote.
00411     if ( url.protocol() == "kmail" && url.path()=="levelquote" )
00412     {
00413       QString levelStr= url.query().mid( 1,url.query().length() );
00414       bool isNumber;
00415       int levelQuote= levelStr.toInt(&isNumber);
00416       if ( isNumber )
00417         w->slotLevelQuote( levelQuote );
00418       return true;
00419     }
00420     return false;
00421   }
00422   QString ExpandCollapseQuoteURLManager::statusBarMessage(
00423       const KURL & url, KMReaderWin * ) const
00424   {
00425       if ( url.protocol() == "kmail" && url.path() == "levelquote" )
00426       {
00427         QString query= url.query();
00428         if ( query.length()>=2 )
00429           if ( query[ 1 ] =='-'  )
00430             return i18n("Expand all quoted text.");
00431           else
00432             return i18n("Collapse quoted text.");
00433       }
00434       return QString::null ;
00435   }
00436 
00437 }
00438 
00439 // defined in kmreaderwin.cpp...
00440 extern bool foundSMIMEData( const QString aUrl, QString & displayName,
00441                 QString & libName, QString & keyId );
00442 
00443 namespace {
00444   bool SMimeURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
00445     if ( !url.hasRef() )
00446       return false;
00447     QString displayName, libName, keyId;
00448     if ( !foundSMIMEData( url.path() + '#' + url.ref(), displayName, libName, keyId ) )
00449       return false;
00450     KProcess cmp;
00451     cmp << "kleopatra" << "-query" << keyId;
00452     if ( !cmp.start( KProcess::DontCare ) )
00453       KMessageBox::error( w, i18n("Could not start certificate manager. "
00454                   "Please check your installation."),
00455               i18n("KMail Error") );
00456     return true;
00457   }
00458 
00459   QString SMimeURLHandler::statusBarMessage( const KURL & url, KMReaderWin * ) const {
00460     QString displayName, libName, keyId;
00461     if ( !foundSMIMEData( url.path() + '#' + url.ref(), displayName, libName, keyId ) )
00462       return QString::null;
00463     return i18n("Show certificate 0x%1").arg( keyId );
00464   }
00465 }
00466 
00467 namespace {
00468   bool HtmlAnchorHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
00469     if ( url.hasHost() || url.path() != "/" || !url.hasRef() )
00470       return false;
00471     if ( w && !w->htmlPart()->gotoAnchor( url.ref() ) )
00472       static_cast<QScrollView*>( w->htmlPart()->widget() )->ensureVisible( 0, 0 );
00473     return true;
00474   }
00475 }
00476 
00477 namespace {
00478   QString MailToURLHandler::statusBarMessage( const KURL & url, KMReaderWin * ) const {
00479     if ( url.protocol() != "mailto" )
00480       return QString::null;
00481     return KMMessage::decodeMailtoUrl( url.url() );
00482   }
00483 }
00484 
00485 namespace {
00486   bool AttachmentURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
00487     if ( !w || !w->message() )
00488       return false;
00489     const int id = KMReaderWin::msgPartFromUrl( url );
00490     if ( id <= 0 )
00491       return false;
00492     w->openAttachment( id, url.path() );
00493     return true;
00494   }
00495 
00496   bool AttachmentURLHandler::handleContextMenuRequest( const KURL & url, const QPoint & p, KMReaderWin * w ) const {
00497     if ( !w || !w->message() )
00498       return false;
00499     const int id = KMReaderWin::msgPartFromUrl( url );
00500     if ( id <= 0 )
00501       return false;
00502     w->showAttachmentPopup( id, url.path(), p );
00503     return true;
00504   }
00505 
00506   QString AttachmentURLHandler::statusBarMessage( const KURL & url, KMReaderWin * w ) const {
00507     if ( !w || !w->message() )
00508       return QString::null;
00509     const partNode * node = w->partNodeFromUrl( url );
00510     if ( !node )
00511       return QString::null;
00512     const KMMessagePart & msgPart = node->msgPart();
00513     QString name = msgPart.fileName();
00514     if ( name.isEmpty() )
00515       name = msgPart.name();
00516     if ( !name.isEmpty() )
00517       return i18n( "Attachment: %1" ).arg( name );
00518     return i18n( "Attachment #%1 (unnamed)" ).arg( KMReaderWin::msgPartFromUrl( url ) );
00519   }
00520 }
00521 
00522 namespace {
00523   bool FallBackURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
00524     if ( w )
00525       w->emitUrlClicked( url, Qt::LeftButton );
00526     return true;
00527   }
00528 
00529   bool FallBackURLHandler::handleContextMenuRequest( const KURL & url, const QPoint & p, KMReaderWin * w ) const {
00530     if ( w )
00531       w->emitPopupMenu( url, p );
00532     return true;
00533   }
00534 }
KDE Home | KDE Accessibility Home | Description of Access Keys