• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDocTools

kio_help.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
00003    Copyright (C) 2001 Stephan Kulow <coolo@kde.org>
00004    Copyright (C) 2003 Cornelius Schumacher <schumacher@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later versio
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 */
00021 
00022 
00023 #include "kio_help.h"
00024 #include <QDir>
00025 
00026 #include <config.h>
00027 
00028 #ifdef HAVE_SYS_TYPES_H
00029 # include <sys/types.h>
00030 #endif
00031 #ifdef HAVE_SYS_STAT_H
00032 # include <sys/stat.h>
00033 #endif
00034 
00035 #include <errno.h>
00036 #include <fcntl.h>
00037 #ifdef HAVE_STDIO_H
00038 # include <stdio.h>
00039 #endif
00040 #ifdef HAVE_STDLIB_H
00041 # include <stdlib.h>
00042 #endif
00043 
00044 #include <QtCore/QFileInfo>
00045 #include <QtCore/QFile>
00046 #include <QtCore/QRegExp>
00047 #include <QtCore/QTextCodec>
00048 #include <QtGui/QTextDocument>
00049 
00050 #include <kdebug.h>
00051 #include <kde_file.h>
00052 #include <kurl.h>
00053 #include <kglobal.h>
00054 #include <klocale.h>
00055 #include <kstandarddirs.h>
00056 #include <kcomponentdata.h>
00057 
00058 #include <libxslt/xsltutils.h>
00059 #include <libxslt/transform.h>
00060 #include "xslt.h"
00061 
00062 using namespace KIO;
00063 
00064 QString HelpProtocol::langLookup(const QString &fname)
00065 {
00066     QStringList search;
00067 
00068     // assemble the local search paths
00069     const QStringList localDoc = KGlobal::dirs()->resourceDirs("html");
00070 
00071     QStringList langs = KGlobal::locale()->languageList();
00072     langs.append( "en" );
00073     langs.removeAll( "C" );
00074 
00075     // this is kind of compat hack as we install our docs in en/ but the
00076     // default language is en_US
00077     for (QStringList::Iterator it = langs.begin(); it != langs.end(); ++it)
00078         if ( *it == "en_US" )
00079             *it = "en";
00080 
00081     // look up the different languages
00082     int ldCount = localDoc.count();
00083     for (int id=0; id < ldCount; id++)
00084     {
00085         QStringList::ConstIterator lang;
00086         for (lang = langs.constBegin(); lang != langs.constEnd(); ++lang)
00087             search.append(QString("%1%2/%3").arg(localDoc[id], *lang, fname));
00088     }
00089 
00090     // try to locate the file
00091     for (QStringList::ConstIterator it = search.constBegin(); it != search.constEnd(); ++it)
00092     {
00093         kDebug( 7119 ) << "Looking for help in: " << *it;
00094 
00095         QFileInfo info(*it);
00096         if (info.exists() && info.isFile() && info.isReadable())
00097             return *it;
00098 
00099         if ( ( *it ).endsWith( ".html" ) )
00100         {
00101             QString file = (*it).left((*it).lastIndexOf('/')) + "/index.docbook";
00102             kDebug( 7119 ) << "Looking for help in: " << file;
00103             info.setFile(file);
00104             if (info.exists() && info.isFile() && info.isReadable())
00105                 return *it;
00106         }
00107     }
00108 
00109 
00110     return QString();
00111 }
00112 
00113 
00114 QString HelpProtocol::lookupFile(const QString &fname,
00115                                  const QString &query, bool &redirect)
00116 {
00117     redirect = false;
00118 
00119     const QString path = fname;
00120 
00121     QString result = langLookup(path);
00122     if (result.isEmpty())
00123     {
00124         result = langLookup(path+"/index.html");
00125         if (!result.isEmpty())
00126     {
00127             KUrl red( "help:/" );
00128             red.setPath( path + "/index.html" );
00129             red.setQuery( query );
00130             redirection(red);
00131             kDebug( 7119 ) << "redirect to " << red.url();
00132             redirect = true;
00133     }
00134         else
00135     {
00136         unicodeError( i18n("There is no documentation available for %1." , Qt::escape(path)) );
00137             return QString();
00138     }
00139     } else
00140         kDebug( 7119 ) << "result " << result;
00141 
00142     return result;
00143 }
00144 
00145 
00146 void HelpProtocol::unicodeError( const QString &t )
00147 {
00148 #ifdef Q_WS_WIN
00149    QString encoding = "UTF-8";
00150 #else
00151    QString encoding = QTextCodec::codecForLocale()->name();
00152 #endif   
00153    data(fromUnicode( QString(
00154         "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\"></head>\n"
00155         "%2</html>" ).arg( encoding, Qt::escape(t) ) ) );
00156      
00157 }
00158 
00159 HelpProtocol *slave = 0;
00160 
00161 HelpProtocol::HelpProtocol( bool ghelp, const QByteArray &pool, const QByteArray &app )
00162   : SlaveBase( ghelp ? "ghelp" : "help", pool, app ), mGhelp( ghelp )
00163 {
00164     slave = this;
00165 }
00166 
00167 void HelpProtocol::get( const KUrl& url )
00168 {
00169     kDebug( 7119 ) << "path=" << url.path()
00170                    << "query=" << url.query();
00171 
00172     bool redirect;
00173     QString doc = QDir::cleanPath(url.path());
00174     if (doc.contains("..")) {
00175         error( KIO::ERR_DOES_NOT_EXIST, url.url() );
00176         return;
00177     }
00178 
00179     if ( !mGhelp ) {
00180         if (!doc.startsWith('/'))
00181             doc = doc.prepend(QLatin1Char('/'));
00182 
00183         if (doc.endsWith('/'))
00184             doc += "index.html";
00185     }
00186 
00187     infoMessage(i18n("Looking up correct file"));
00188 
00189     if ( !mGhelp ) {
00190       doc = lookupFile(doc, url.query(), redirect);
00191 
00192       if (redirect)
00193       {
00194           finished();
00195           return;
00196       }
00197     }
00198 
00199     if (doc.isEmpty())
00200     {
00201         error( KIO::ERR_DOES_NOT_EXIST, url.url() );
00202         return;
00203     }
00204 
00205     mimeType("text/html");
00206     KUrl target;
00207     target.setPath(doc);
00208     if (url.hasHTMLRef())
00209         target.setHTMLRef(url.htmlRef());
00210 
00211     kDebug( 7119 ) << "target " << target.url();
00212 
00213     QString file = target.scheme() == "file" ? target.toLocalFile() : target.path();
00214     
00215     if ( mGhelp ) {
00216       if ( !file.endsWith( QLatin1String( ".xml" ) ) ) {
00217          get_file( target );
00218          return;
00219       }
00220     } else {
00221         QString docbook_file = file.left(file.lastIndexOf('/')) + "/index.docbook";
00222         if (!KStandardDirs::exists(file)) {
00223             file = docbook_file;
00224         } else {
00225             QFileInfo fi(file);
00226             if (fi.isDir()) {
00227                 file = file + "/index.docbook";
00228             } else {
00229                 if ( !file.endsWith( QLatin1String( ".html" ) ) || !compareTimeStamps( file, docbook_file ) ) {
00230                     get_file( target );
00231                     return;
00232                 } else
00233                     file = docbook_file;
00234             }
00235         }
00236     }
00237 
00238     infoMessage(i18n("Preparing document"));
00239 
00240     if ( mGhelp ) {
00241         QString xsl = "customization/kde-nochunk.xsl";
00242         mParsed = transform(file, KStandardDirs::locate("dtd", xsl));
00243 
00244         kDebug( 7119 ) << "parsed " << mParsed.length();
00245 
00246         if (mParsed.isEmpty()) {
00247             unicodeError( i18n( "The requested help file could not be parsed:<br />%1" ,  file ) );
00248         } else {
00249             int pos1 = mParsed.indexOf( "charset=" );
00250             if ( pos1 > 0 ) {
00251               int pos2 = mParsed.indexOf( '"', pos1 );
00252               if ( pos2 > 0 ) {
00253                 mParsed.replace( pos1, pos2 - pos1, "charset=UTF-8" );
00254               }
00255             }
00256             data( mParsed.toUtf8() );
00257         }
00258     } else {
00259 
00260         kDebug( 7119 ) << "look for cache for " << file;
00261 
00262         mParsed = lookForCache( file );
00263 
00264         kDebug( 7119 ) << "cached parsed " << mParsed.length();
00265 
00266         if ( mParsed.isEmpty() ) {
00267             mParsed = transform(file, KStandardDirs::locate("dtd", "customization/kde-chunk.xsl"));
00268             if ( !mParsed.isEmpty() ) {
00269                 infoMessage( i18n( "Saving to cache" ) );
00270 #ifdef Q_WS_WIN
00271                 QFileInfo fi(file);
00272                 // make sure filenames do not contain the base path, otherwise
00273                 // accessing user data from another location invalids cached files
00274                 // Accessing user data under a different path is possible
00275                 // when using usb sticks - this may affect unix/mac systems also
00276                 QString cache = '/' + fi.absolutePath().remove(KStandardDirs::installPath("html"),Qt::CaseInsensitive).replace('/','_') + '_' + fi.baseName() + '.';
00277 #else
00278                 QString cache = file.left( file.length() - 7 );
00279 #endif
00280                 saveToCache( mParsed, KStandardDirs::locateLocal( "cache",
00281                                                                   "kio_help" + cache +
00282                                                                   "cache.bz2" ) );
00283             }
00284         } else infoMessage( i18n( "Using cached version" ) );
00285 
00286         kDebug( 7119 ) << "parsed " << mParsed.length();
00287 
00288         if (mParsed.isEmpty()) {
00289             unicodeError( i18n( "The requested help file could not be parsed:<br />%1" ,  file ) );
00290         } else {
00291             QString query = url.query(), anchor;
00292 
00293             // if we have a query, look if it contains an anchor
00294             if (!query.isEmpty())
00295                 if (query.startsWith("?anchor=")) {
00296                     anchor = query.mid(8).toLower();
00297 
00298                 KUrl redirURL(url);
00299 
00300                 redirURL.setQuery(QString());
00301                 redirURL.setHTMLRef(anchor);
00302                 redirection(redirURL);
00303                 finished();
00304                 return;
00305             }
00306             if (anchor.isEmpty() && url.hasHTMLRef())
00307             anchor = url.htmlRef();
00308 
00309             kDebug( 7119 ) << "anchor: " << anchor;
00310 
00311             if ( !anchor.isEmpty() )
00312             {
00313                 int index = 0;
00314                 while ( true ) {
00315                     index = mParsed.indexOf( QRegExp( "<a name=" ), index);
00316                     if ( index == -1 ) {
00317                         kDebug( 7119 ) << "no anchor\n";
00318                         break; // use whatever is the target, most likely index.html
00319                     }
00320 
00321                     if ( mParsed.mid( index, 11 + anchor.length() ).toLower() ==
00322                          QString( "<a name=\"%1\">" ).arg( anchor ) )
00323                     {
00324                         index = mParsed.lastIndexOf( "<FILENAME filename=", index ) +
00325                                  strlen( "<FILENAME filename=\"" );
00326                         QString filename=mParsed.mid( index, 2000 );
00327                         filename = filename.left( filename.indexOf( '\"' ) );
00328                         QString path = target.path();
00329                         path = path.left( path.lastIndexOf( '/' ) + 1) + filename;
00330                         target.setPath( path );
00331                         kDebug( 7119 ) << "anchor found in " << target.url();
00332                         break;
00333                     }
00334                     index++;
00335                 }
00336             }
00337             emitFile( target );
00338         }
00339     }
00340 
00341     finished();
00342 }
00343 
00344 void HelpProtocol::emitFile( const KUrl& url )
00345 {
00346     infoMessage(i18n("Looking up section"));
00347 
00348     QString filename = url.path().mid(url.path().lastIndexOf('/') + 1);
00349 
00350     int index = mParsed.indexOf(QString("<FILENAME filename=\"%1\"").arg(filename));
00351     if (index == -1) {
00352         if ( filename == "index.html" ) {
00353             data( fromUnicode( mParsed ) );
00354             return;
00355         }
00356 
00357         unicodeError( i18n("Could not find filename %1 in %2.", filename,  url.url() ) );
00358         return;
00359     }
00360 
00361     QString filedata = splitOut(mParsed, index);
00362     replaceCharsetHeader( filedata );
00363 
00364     data( fromUnicode( filedata ) );
00365     data( QByteArray() );
00366 }
00367 
00368 void HelpProtocol::mimetype( const KUrl &)
00369 {
00370     mimeType("text/html");
00371     finished();
00372 }
00373 
00374 // Copied from kio_file to avoid redirects
00375 
00376 #define MAX_IPC_SIZE (1024*32)
00377 
00378 void HelpProtocol::get_file( const KUrl& url )
00379 {
00380     kDebug( 7119 ) << "get_file " << url.url();
00381 
00382 #ifdef Q_WS_WIN
00383     QFile f( url.toLocalFile() );
00384     if ( !f.exists() ) {
00385         error( KIO::ERR_DOES_NOT_EXIST, url.url() );
00386         return;
00387     }
00388     if ( !f.open(QIODevice::ReadOnly) ) {
00389         error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
00390         return;
00391     }
00392     int processed_size = 0;
00393     totalSize( f.size() );
00394 
00395     QByteArray array;
00396     array.resize(MAX_IPC_SIZE);
00397 
00398     while( 1 )
00399     {
00400         qint64 n = f.read(array.data(),array.size());
00401         if (n == -1) {
00402             error( KIO::ERR_COULD_NOT_READ, url.path());
00403             f.close();
00404             return;
00405        }
00406        if (n == 0)
00407             break; // Finished
00408 
00409        data( array );
00410 
00411        processed_size += n;
00412        processedSize( processed_size );
00413     }
00414 
00415     data( QByteArray() );
00416     f.close();
00417 
00418     processedSize( f.size() );
00419     finished();
00420 #else
00421     QByteArray _path( QFile::encodeName(url.path()));
00422     KDE_struct_stat buff;
00423     if ( KDE_stat( _path.data(), &buff ) == -1 ) {
00424         if ( errno == EACCES )
00425            error( KIO::ERR_ACCESS_DENIED, url.url() );
00426         else
00427            error( KIO::ERR_DOES_NOT_EXIST, url.url() );
00428         return;
00429     }
00430 
00431     if ( S_ISDIR( buff.st_mode ) ) {
00432         error( KIO::ERR_IS_DIRECTORY, url.path() );
00433         return;
00434     }
00435     if ( S_ISFIFO( buff.st_mode ) || S_ISSOCK ( buff.st_mode ) ) {
00436         error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
00437         return;
00438     }
00439 
00440     int fd = KDE_open( _path.data(), O_RDONLY);
00441     if ( fd < 0 ) {
00442         error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
00443         return;
00444     }
00445 
00446     totalSize( buff.st_size );
00447     int processed_size = 0;
00448 
00449     char buffer[ MAX_IPC_SIZE ];
00450     QByteArray array;
00451 
00452     while( 1 )
00453     {
00454        int n = ::read( fd, buffer, MAX_IPC_SIZE );
00455        if (n == -1)
00456        {
00457           if (errno == EINTR)
00458               continue;
00459           error( KIO::ERR_COULD_NOT_READ, url.path());
00460           ::close(fd);
00461           return;
00462        }
00463        if (n == 0)
00464           break; // Finished
00465 
00466        array = array.fromRawData(buffer, n);
00467        data( array );
00468        array = array.fromRawData(buffer, n);
00469 
00470        processed_size += n;
00471        processedSize( processed_size );
00472     }
00473 
00474     data( QByteArray() );
00475 
00476     ::close( fd );
00477 
00478     processedSize( buff.st_size );
00479 
00480     finished();
00481 #endif
00482 }

KDocTools

Skip menu "KDocTools"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal