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

KDocTools

kio_help.cpp

Go to the documentation of this file.
00001 #include <config.h>
00002 
00003 #ifdef HAVE_SYS_TYPES_H
00004 # include <sys/types.h>
00005 #endif
00006 #ifdef HAVE_SYS_STAT_H
00007 # include <sys/stat.h>
00008 #endif
00009 
00010 #include <errno.h>
00011 #include <fcntl.h>
00012 #ifdef HAVE_STDIO_H
00013 # include <stdio.h>
00014 #endif
00015 #ifdef HAVE_STDLIB_H
00016 # include <stdlib.h>
00017 #endif
00018 
00019 #include <qvaluelist.h>
00020 #include <qfileinfo.h>
00021 #include <qfile.h>
00022 #include <qtextstream.h>
00023 #include <qregexp.h>
00024 #include <qtextcodec.h>
00025 
00026 #include <kdebug.h>
00027 #include <kurl.h>
00028 #include <kglobal.h>
00029 #include <klocale.h>
00030 #include <kstandarddirs.h>
00031 #include <kinstance.h>
00032 
00033 #include "kio_help.h"
00034 #include <libxslt/xsltutils.h>
00035 #include <libxslt/transform.h>
00036 #include "xslt.h"
00037 
00038 using namespace KIO;
00039 
00040 QString HelpProtocol::langLookup(const QString& fname)
00041 {
00042     QStringList search;
00043 
00044     // assemble the local search paths
00045     const QStringList localDoc = KGlobal::dirs()->resourceDirs("html");
00046 
00047     QStringList langs = KGlobal::locale()->languageList();
00048     langs.append( "en" );
00049     langs.remove( "C" );
00050 
00051     // this is kind of compat hack as we install our docs in en/ but the
00052     // default language is en_US
00053     for (QStringList::Iterator it = langs.begin(); it != langs.end(); ++it)
00054         if ( *it == "en_US" )
00055             *it = "en";
00056 
00057     // look up the different languages
00058     int ldCount = localDoc.count();
00059     for (int id=0; id < ldCount; id++)
00060     {
00061         QStringList::ConstIterator lang;
00062         for (lang = langs.begin(); lang != langs.end(); ++lang)
00063             search.append(QString("%1%2/%3").arg(localDoc[id], *lang, fname));
00064     }
00065 
00066     // try to locate the file
00067     QStringList::Iterator it;
00068     for (it = search.begin(); it != search.end(); ++it)
00069     {
00070         kdDebug( 7119 ) << "Looking for help in: " << *it << endl;
00071 
00072         QFileInfo info(*it);
00073         if (info.exists() && info.isFile() && info.isReadable())
00074             return *it;
00075 
00076         if ( ( *it ).right( 5 ) == ".html" )
00077         {
00078             QString file = (*it).left((*it).findRev('/')) + "/index.docbook";
00079             kdDebug( 7119 ) << "Looking for help in: " << file << endl;
00080             info.setFile(file);
00081             if (info.exists() && info.isFile() && info.isReadable())
00082                 return *it;
00083         }
00084     }
00085 
00086 
00087     return QString::null;
00088 }
00089 
00090 
00091 QString HelpProtocol::lookupFile(const QString &fname,
00092                                  const QString &query, bool &redirect)
00093 {
00094     redirect = false;
00095 
00096     QString path, result;
00097 
00098     path = fname;
00099 
00100     result = langLookup(path);
00101     if (result.isEmpty())
00102     {
00103         result = langLookup(path+"/index.html");
00104         if (!result.isEmpty())
00105     {
00106             KURL red( "help:/" );
00107             red.setPath( path + "/index.html" );
00108             red.setQuery( query );
00109             redirection(red);
00110             kdDebug( 7119 ) << "redirect to " << red.url() << endl;
00111             redirect = true;
00112     }
00113         else
00114     {
00115         unicodeError( i18n("There is no documentation available for %1." ).arg(path) );
00116         finished();
00117             return QString::null;
00118     }
00119     } else
00120         kdDebug( 7119 ) << "result " << result << endl;
00121 
00122     return result;
00123 }
00124 
00125 
00126 void HelpProtocol::unicodeError( const QString &t )
00127 {
00128    data(fromUnicode( QString(
00129         "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\"></head>\n"
00130         "%2</html>" ).arg( QTextCodec::codecForLocale()->name() ).arg( t ) ) );
00131 }
00132 
00133 HelpProtocol *slave = 0;
00134 
00135 HelpProtocol::HelpProtocol( bool ghelp, const QCString &pool, const QCString &app )
00136   : SlaveBase( ghelp ? "ghelp" : "help", pool, app ), mGhelp( ghelp )
00137 {
00138     slave = this;
00139 }
00140 
00141 void HelpProtocol::get( const KURL& url )
00142 {
00143     kdDebug( 7119 ) << "get: path=" << url.path()
00144               << " query=" << url.query() << endl;
00145 
00146     bool redirect;
00147     QString doc;
00148     doc = url.path();
00149 
00150     if ( !mGhelp ) {
00151         if (doc.at(0) != '/')
00152             doc = doc.prepend('/');
00153 
00154         if (doc.at(doc.length() - 1) == '/')
00155             doc += "index.html";
00156     }
00157 
00158     infoMessage(i18n("Looking up correct file"));
00159 
00160     if ( !mGhelp ) {
00161       doc = lookupFile(doc, url.query(), redirect);
00162 
00163       if (redirect)
00164       {
00165           finished();
00166           return;
00167       }
00168     }
00169 
00170     if (doc.isEmpty())
00171     {
00172         error( KIO::ERR_DOES_NOT_EXIST, url.url() );
00173         return;
00174     }
00175 
00176     mimeType("text/html");
00177     KURL target;
00178     target.setPath(doc);
00179     if (url.hasHTMLRef())
00180         target.setHTMLRef(url.htmlRef());
00181 
00182     kdDebug( 7119 ) << "target " << target.url() << endl;
00183 
00184     QString file = target.path();
00185     
00186     if ( mGhelp ) {
00187       if ( file.right( 4 ) != ".xml" ) {
00188          get_file( target );
00189          return;
00190       }
00191     } else {
00192         QString docbook_file = file.left(file.findRev('/')) + "/index.docbook";
00193         if (!KStandardDirs::exists(file)) {
00194             file = docbook_file;
00195         } else {
00196             QFileInfo fi(file);
00197             if (fi.isDir()) {
00198                 file = file + "/index.docbook";
00199             } else {
00200                 if ( file.right( 5 ) != ".html" || !compareTimeStamps( file, docbook_file ) ) {
00201                     get_file( target );
00202                     return;
00203                 } else
00204                     file = docbook_file;
00205             }
00206         }
00207     }
00208 
00209     infoMessage(i18n("Preparing document"));
00210 
00211     if ( mGhelp ) {
00212         QString xsl = "customization/kde-nochunk.xsl";
00213         mParsed = transform(file, locate("dtd", xsl));
00214 
00215         kdDebug( 7119 ) << "parsed " << mParsed.length() << endl;
00216 
00217         if (mParsed.isEmpty()) {
00218             unicodeError( i18n( "The requested help file could not be parsed:<br>%1" ).arg( file ) );
00219         } else {
00220             int pos1 = mParsed.find( "charset=" );
00221             if ( pos1 > 0 ) {
00222               int pos2 = mParsed.find( '"', pos1 );
00223               if ( pos2 > 0 ) {
00224                 mParsed.replace( pos1, pos2 - pos1, "charset=UTF-8" );
00225               }
00226             }
00227             data( mParsed.utf8() );
00228         }
00229     } else {
00230 
00231         kdDebug( 7119 ) << "look for cache for " << file << endl;
00232 
00233         mParsed = lookForCache( file );
00234 
00235         kdDebug( 7119 ) << "cached parsed " << mParsed.length() << endl;
00236 
00237         if ( mParsed.isEmpty() ) {
00238             mParsed = transform(file, locate("dtd", "customization/kde-chunk.xsl"));
00239             if ( !mParsed.isEmpty() ) {
00240                 infoMessage( i18n( "Saving to cache" ) );
00241                 QString cache = file.left( file.length() - 7 );
00242                 saveToCache( mParsed, locateLocal( "cache",
00243                                                         "kio_help" + cache +
00244                                                         "cache.bz2" ) );
00245             }
00246         } else infoMessage( i18n( "Using cached version" ) );
00247 
00248         kdDebug( 7119 ) << "parsed " << mParsed.length() << endl;
00249 
00250         if (mParsed.isEmpty()) {
00251             unicodeError( i18n( "The requested help file could not be parsed:<br>%1" ).arg( file ) );
00252         } else {
00253             QString query = url.query(), anchor;
00254 
00255             // if we have a query, look if it contains an anchor
00256             if (!query.isEmpty())
00257                 if (query.left(8) == "?anchor=") {
00258                     anchor = query.mid(8).lower();
00259 
00260                 KURL redirURL(url);
00261 
00262                 redirURL.setQuery(QString::null);
00263                 redirURL.setHTMLRef(anchor);
00264                 redirection(redirURL);
00265                 finished();
00266                 return;
00267             }
00268             if (anchor.isEmpty() && url.hasHTMLRef())
00269             anchor = url.htmlRef();
00270 
00271             kdDebug( 7119 ) << "anchor: " << anchor << endl;
00272 
00273             if ( !anchor.isEmpty() )
00274             {
00275                 int index = 0;
00276                 while ( true ) {
00277                     index = mParsed.find( QRegExp( "<a name=" ), index);
00278                     if ( index == -1 ) {
00279                         kdDebug( 7119 ) << "no anchor\n";
00280                         break; // use whatever is the target, most likely index.html
00281                     }
00282 
00283                     if ( mParsed.mid( index, 11 + anchor.length() ).lower() ==
00284                          QString( "<a name=\"%1\">" ).arg( anchor ) )
00285                     {
00286                         index = mParsed.findRev( "<FILENAME filename=", index ) +
00287                                  strlen( "<FILENAME filename=\"" );
00288                         QString filename=mParsed.mid( index, 2000 );
00289                         filename = filename.left( filename.find( '\"' ) );
00290                         QString path = target.path();
00291                         path = path.left( path.findRev( '/' ) + 1) + filename;
00292                         kdDebug( 7119 ) << "anchor found in " << path <<endl;
00293                         target.setPath( path );
00294                         break;
00295                     }
00296                     index++;
00297                 }
00298             }
00299             emitFile( target );
00300         }
00301     }
00302 
00303     finished();
00304 }
00305 
00306 void HelpProtocol::emitFile( const KURL& url )
00307 {
00308     infoMessage(i18n("Looking up section"));
00309 
00310     QString filename = url.path().mid(url.path().findRev('/') + 1);
00311 
00312     int index = mParsed.find(QString("<FILENAME filename=\"%1\"").arg(filename));
00313     if (index == -1) {
00314         if ( filename == "index.html" ) {
00315             data( fromUnicode( mParsed ) );
00316             return;
00317         }
00318 
00319         unicodeError( i18n("Could not find filename %1 in %2.").arg(filename).arg( url.url() ) );
00320         return;
00321     }
00322 
00323     QString filedata = splitOut(mParsed, index);
00324     replaceCharsetHeader( filedata );
00325 
00326     data( fromUnicode( filedata ) );
00327     data( QByteArray() );
00328 }
00329 
00330 void HelpProtocol::mimetype( const KURL &)
00331 {
00332     mimeType("text/html");
00333     finished();
00334 }
00335 
00336 // Copied from kio_file to avoid redirects
00337 
00338 #define MAX_IPC_SIZE (1024*32)
00339 
00340 void HelpProtocol::get_file( const KURL& url )
00341 {
00342     kdDebug( 7119 ) << "get_file " << url.url() << endl;
00343 
00344     QCString _path( QFile::encodeName(url.path()));
00345     struct stat buff;
00346     if ( ::stat( _path.data(), &buff ) == -1 ) {
00347         if ( errno == EACCES )
00348            error( KIO::ERR_ACCESS_DENIED, url.path() );
00349         else
00350            error( KIO::ERR_DOES_NOT_EXIST, url.path() );
00351     return;
00352     }
00353 
00354     if ( S_ISDIR( buff.st_mode ) ) {
00355     error( KIO::ERR_IS_DIRECTORY, url.path() );
00356     return;
00357     }
00358     if ( S_ISFIFO( buff.st_mode ) || S_ISSOCK ( buff.st_mode ) ) {
00359     error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
00360     return;
00361     }
00362 
00363     int fd = open( _path.data(), O_RDONLY);
00364     if ( fd < 0 ) {
00365     error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
00366     return;
00367     }
00368 
00369     totalSize( buff.st_size );
00370     int processed_size = 0;
00371 
00372     char buffer[ MAX_IPC_SIZE ];
00373     QByteArray array;
00374 
00375     while( 1 )
00376     {
00377        int n = ::read( fd, buffer, MAX_IPC_SIZE );
00378        if (n == -1)
00379        {
00380           if (errno == EINTR)
00381               continue;
00382           error( KIO::ERR_COULD_NOT_READ, url.path());
00383           close(fd);
00384           return;
00385        }
00386        if (n == 0)
00387           break; // Finished
00388 
00389        array.setRawData(buffer, n);
00390        data( array );
00391        array.resetRawData(buffer, n);
00392 
00393        processed_size += n;
00394        processedSize( processed_size );
00395     }
00396 
00397     data( QByteArray() );
00398 
00399     close( fd );
00400 
00401     processedSize( buff.st_size );
00402 
00403     finished();
00404 }

KDocTools

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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