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() == "startIMApp" )
00364 //       {
00365 //         kmkernel->imProxy()->startPreferredApp();
00366 //         return true;
00367 //       }
00368 //       //FIXME: handle startIMApp urls in their own handler, or rename this one
00369     }
00370     return false;
00371   }
00372 
00373   QString ShowHtmlSwitchURLHandler::statusBarMessage( const KURL & url, KMReaderWin * ) const {
00374     if ( url.protocol() == "kmail" )
00375     {
00376       if ( url.path() == "showHTML" )
00377         return i18n("Turn on HTML rendering for this message.");
00378       if ( url.path() == "loadExternal" )
00379         return i18n("Load external references from the Internet for this message.");
00380       if ( url.path() == "goOnline" )
00381         return i18n("Work online");
00382     }
00383     return QString::null ;
00384   }
00385 }
00386 
00387 namespace {
00388 
00389   bool ExpandCollapseQuoteURLManager::handleClick( 
00390       const KURL & url, KMReaderWin * w ) const 
00391   {
00392     //  kmail:levelquote/?num      -> the level quote to collapse.
00393     //  kmail:levelquote/?-num      -> expand all levels quote.
00394     if ( url.protocol() == "kmail" && url.path()=="levelquote" ) 
00395     {
00396       QString levelStr= url.query().mid( 1,url.query().length() );
00397       bool isNumber;
00398       int levelQuote= levelStr.toInt(&isNumber);
00399       if ( isNumber )
00400         w->slotLevelQuote( levelQuote );
00401       return true;
00402     }
00403     return false;
00404   }
00405   QString ExpandCollapseQuoteURLManager::statusBarMessage( 
00406       const KURL & url, KMReaderWin * ) const 
00407   {
00408       if ( url.protocol() == "kmail" && url.path() == "levelquote" )
00409       {
00410         QString query= url.query();
00411         if ( query.length()>=2 )
00412           if ( query[ 1 ] =='-'  )
00413             return i18n("Expand all quoted text.");
00414           else
00415             return i18n("Collapse quoted text.");
00416       }
00417       return QString::null ;
00418   }
00419 
00420 }
00421 
00422 // defined in kmreaderwin.cpp...
00423 extern bool foundSMIMEData( const QString aUrl, QString & displayName,
00424                 QString & libName, QString & keyId );
00425 
00426 namespace {
00427   bool SMimeURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
00428     if ( !url.hasRef() )
00429       return false;
00430     QString displayName, libName, keyId;
00431     if ( !foundSMIMEData( url.path() + '#' + url.ref(), displayName, libName, keyId ) )
00432       return false;
00433     KProcess cmp;
00434     cmp << "kleopatra" << "-query" << keyId;
00435     if ( !cmp.start( KProcess::DontCare ) )
00436       KMessageBox::error( w, i18n("Could not start certificate manager. "
00437                   "Please check your installation."),
00438               i18n("KMail Error") );
00439     return true;
00440   }
00441 
00442   QString SMimeURLHandler::statusBarMessage( const KURL & url, KMReaderWin * ) const {
00443     QString displayName, libName, keyId;
00444     if ( !foundSMIMEData( url.path() + '#' + url.ref(), displayName, libName, keyId ) )
00445       return QString::null;
00446     return i18n("Show certificate 0x%1").arg( keyId );
00447   }
00448 }
00449 
00450 namespace {
00451   bool HtmlAnchorHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
00452     if ( url.hasHost() || url.path() != "/" || !url.hasRef() )
00453       return false;
00454     if ( w && !w->htmlPart()->gotoAnchor( url.ref() ) )
00455       static_cast<QScrollView*>( w->htmlPart()->widget() )->ensureVisible( 0, 0 );
00456     return true;
00457   }
00458 }
00459 
00460 namespace {
00461   QString MailToURLHandler::statusBarMessage( const KURL & url, KMReaderWin * ) const {
00462     if ( url.protocol() != "mailto" )
00463       return QString::null;
00464     return KMMessage::decodeMailtoUrl( url.url() );
00465   }
00466 }
00467 
00468 namespace {
00469   bool AttachmentURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
00470     if ( !w || !w->message() )
00471       return false;
00472     const int id = KMReaderWin::msgPartFromUrl( url );
00473     if ( id <= 0 )
00474       return false;
00475     w->openAttachment( id, url.path() );
00476     return true;
00477   }
00478 
00479   bool AttachmentURLHandler::handleContextMenuRequest( const KURL & url, const QPoint & p, KMReaderWin * w ) const {
00480     if ( !w || !w->message() )
00481       return false;
00482     const int id = KMReaderWin::msgPartFromUrl( url );
00483     if ( id <= 0 )
00484       return false;
00485     w->showAttachmentPopup( id, url.path(), p );
00486     return true;
00487   }
00488 
00489   QString AttachmentURLHandler::statusBarMessage( const KURL & url, KMReaderWin * w ) const {
00490     if ( !w || !w->message() )
00491       return QString::null;
00492     const partNode * node = w->partNodeFromUrl( url );
00493     if ( !node )
00494       return QString::null;
00495     const KMMessagePart & msgPart = node->msgPart();
00496     QString name = msgPart.fileName();
00497     if ( name.isEmpty() )
00498       name = msgPart.name();
00499     if ( !name.isEmpty() )
00500       return i18n( "Attachment: %1" ).arg( name );
00501     return i18n( "Attachment #%1 (unnamed)" ).arg( KMReaderWin::msgPartFromUrl( url ) );
00502   }
00503 }
00504 
00505 namespace {
00506   bool FallBackURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
00507     if ( w )
00508       w->emitUrlClicked( url, Qt::LeftButton );
00509     return true;
00510   }
00511 
00512   bool FallBackURLHandler::handleContextMenuRequest( const KURL & url, const QPoint & p, KMReaderWin * w ) const {
00513     if ( w )
00514       w->emitPopupMenu( url, p );
00515     return true;
00516   }
00517 }
KDE Home | KDE Accessibility Home | Description of Access Keys