# include <config.h>
# ifdef HAVE_SYS_TYPES_H
# include <sys / types.h>
# endif
# ifdef HAVE_SYS_STAT_H
# include <sys / stat.h>
# endif
# include <errno.h>
# include <fcntl.h>
# ifdef HAVE_STDIO_H
# include <stdio.h>
# endif
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
# include <tqvaluelist.h>
# include <tqfileinfo.h>
# include <tqfile.h>
# include <tqtextstream.h>
# include <tqregexp.h>
# include <tqtextcodec.h>
# include <kdebug.h>
# include <kurl.h>
# include <tdeglobal.h>
# include <tdelocale.h>
# include <kstandarddirs.h>
# include <kinstance.h>
# include "tdeio_help.h"
# include <libxslt/xsltutils.h>
# include <libxslt/transform.h>
# include "xslt.h"
using namespace TDEIO ;
TQString HelpProtocol : : langLookup ( const TQString & fname )
{
TQStringList search ;
// assemble the local search paths
const TQStringList localDoc = TDEGlobal : : dirs ( ) - > resourceDirs ( " html " ) + TDEGlobal : : dirs ( ) - > resourceDirs ( " html-bundle " ) ;
TQStringList langs = TDEGlobal : : locale ( ) - > languageList ( ) ;
langs . append ( " en " ) ;
langs . remove ( " C " ) ;
// this is kind of compat hack as we install our docs in en/ but the
// default language is en_US
for ( TQStringList : : Iterator it = langs . begin ( ) ; it ! = langs . end ( ) ; + + it )
if ( * it = = " en_US " )
* it = " en " ;
// look up the different languages
int ldCount = localDoc . count ( ) ;
for ( int id = 0 ; id < ldCount ; id + + )
{
TQStringList : : ConstIterator lang ;
for ( lang = langs . begin ( ) ; lang ! = langs . end ( ) ; + + lang )
search . append ( TQString ( " %1%2/%3 " ) . arg ( localDoc [ id ] , * lang , fname ) ) ;
}
// try to locate the file
TQStringList : : Iterator it ;
for ( it = search . begin ( ) ; it ! = search . end ( ) ; + + it )
{
kdDebug ( 7119 ) < < " Looking for help in: " < < * it < < endl ;
TQFileInfo info ( * it ) ;
if ( info . exists ( ) & & info . isFile ( ) & & info . isReadable ( ) )
return * it ;
if ( ( * it ) . right ( 5 ) = = " .html " )
{
TQString file = ( * it ) . left ( ( * it ) . findRev ( ' / ' ) ) + " /index.docbook " ;
kdDebug ( 7119 ) < < " Looking for help in: " < < file < < endl ;
info . setFile ( file ) ;
if ( info . exists ( ) & & info . isFile ( ) & & info . isReadable ( ) )
return * it ;
}
}
return TQString : : null ;
}
TQString HelpProtocol : : lookupFile ( const TQString & fname ,
const TQString & query , bool & redirect )
{
redirect = false ;
TQString path , result ;
path = fname ;
result = langLookup ( path ) ;
if ( result . isEmpty ( ) )
{
result = langLookup ( path + " /index.html " ) ;
if ( ! result . isEmpty ( ) )
{
KURL red ( " help:/ " ) ;
red . setPath ( path + " /index.html " ) ;
red . setQuery ( query ) ;
redirection ( red ) ;
kdDebug ( 7119 ) < < " redirect to " < < red . url ( ) < < endl ;
redirect = true ;
}
else
{
unicodeError ( i18n ( " There is no documentation available for %1. " ) . arg ( path ) ) ;
finished ( ) ;
return TQString : : null ;
}
} else
kdDebug ( 7119 ) < < " result " < < result < < endl ;
return result ;
}
void HelpProtocol : : unicodeError ( const TQString & t )
{
data ( fromUnicode ( TQString (
" <html><head><meta http-equiv= \" Content-Type \" content= \" text/html; charset=%1 \" ></head> \n "
" %2</html> " ) . arg ( TQTextCodec : : codecForLocale ( ) - > name ( ) ) . arg ( t ) ) ) ;
}
HelpProtocol * slave = 0 ;
HelpProtocol : : HelpProtocol ( bool ghelp , const TQCString & pool , const TQCString & app )
: SlaveBase ( ghelp ? " ghelp " : " help " , pool , app ) , mGhelp ( ghelp )
{
slave = this ;
}
void HelpProtocol : : get ( const KURL & url )
{
kdDebug ( 7119 ) < < " get: path= " < < url . path ( )
< < " query= " < < url . query ( ) < < endl ;
bool redirect ;
TQString doc ;
doc = url . path ( ) ;
if ( ! mGhelp ) {
if ( doc . at ( 0 ) ! = ' / ' )
doc = doc . prepend ( ' / ' ) ;
if ( doc . at ( doc . length ( ) - 1 ) = = ' / ' )
doc + = " index.html " ;
}
infoMessage ( i18n ( " Looking up correct file " ) ) ;
if ( ! mGhelp ) {
doc = lookupFile ( doc , url . query ( ) , redirect ) ;
if ( redirect )
{
finished ( ) ;
return ;
}
}
if ( doc . isEmpty ( ) )
{
error ( TDEIO : : ERR_DOES_NOT_EXIST , url . url ( ) ) ;
return ;
}
mimeType ( " text/html " ) ;
KURL target ;
target . setPath ( doc ) ;
if ( url . hasHTMLRef ( ) )
target . setHTMLRef ( url . htmlRef ( ) ) ;
kdDebug ( 7119 ) < < " target " < < target . url ( ) < < endl ;
TQString file = target . path ( ) ;
if ( mGhelp ) {
if ( file . right ( 4 ) ! = " .xml " ) {
get_file ( target ) ;
return ;
}
} else {
TQString docbook_file = file . left ( file . findRev ( ' / ' ) ) + " /index.docbook " ;
if ( ! TDEStandardDirs : : exists ( file ) ) {
file = docbook_file ;
} else {
TQFileInfo fi ( file ) ;
if ( fi . isDir ( ) ) {
file = file + " /index.docbook " ;
} else {
if ( file . right ( 5 ) ! = " .html " | | ! compareTimeStamps ( file , docbook_file ) ) {
get_file ( target ) ;
return ;
} else
file = docbook_file ;
}
}
}
infoMessage ( i18n ( " Preparing document " ) ) ;
if ( mGhelp ) {
TQString xsl = " customization/kde-nochunk.xsl " ;
mParsed = transform ( file , locate ( " dtd " , xsl ) ) ;
kdDebug ( 7119 ) < < " parsed " < < mParsed . length ( ) < < endl ;
if ( mParsed . isEmpty ( ) ) {
unicodeError ( i18n ( " The requested help file could not be parsed:<br>%1 " ) . arg ( file ) ) ;
} else {
int pos1 = mParsed . find ( " charset= " ) ;
if ( pos1 > 0 ) {
int pos2 = mParsed . find ( ' " ' , pos1 ) ;
if ( pos2 > 0 ) {
mParsed . replace ( pos1 , pos2 - pos1 , " charset=UTF-8 " ) ;
}
}
data ( mParsed . utf8 ( ) ) ;
}
} else {
kdDebug ( 7119 ) < < " look for cache for " < < file < < endl ;
mParsed = lookForCache ( file ) ;
kdDebug ( 7119 ) < < " cached parsed " < < mParsed . length ( ) < < endl ;
if ( mParsed . isEmpty ( ) ) {
mParsed = transform ( file , locate ( " dtd " , " customization/kde-chunk.xsl " ) ) ;
if ( ! mParsed . isEmpty ( ) ) {
infoMessage ( i18n ( " Saving to cache " ) ) ;
TQString cache = file . left ( file . length ( ) - 7 ) ;
saveToCache ( mParsed , locateLocal ( " cache " ,
" tdeio_help " + cache +
" cache.bz2 " ) ) ;
}
} else infoMessage ( i18n ( " Using cached version " ) ) ;
kdDebug ( 7119 ) < < " parsed " < < mParsed . length ( ) < < endl ;
if ( mParsed . isEmpty ( ) ) {
unicodeError ( i18n ( " The requested help file could not be parsed:<br>%1 " ) . arg ( file ) ) ;
} else {
TQString query = url . query ( ) , anchor ;
// if we have a query, look if it contains an anchor
if ( ! query . isEmpty ( ) )
if ( query . left ( 8 ) = = " ?anchor= " ) {
anchor = query . mid ( 8 ) . lower ( ) ;
KURL redirURL ( url ) ;
redirURL . setQuery ( TQString : : null ) ;
redirURL . setHTMLRef ( anchor ) ;
redirection ( redirURL ) ;
finished ( ) ;
return ;
}
if ( anchor . isEmpty ( ) & & url . hasHTMLRef ( ) )
anchor = url . htmlRef ( ) ;
kdDebug ( 7119 ) < < " anchor: " < < anchor < < endl ;
if ( ! anchor . isEmpty ( ) )
{
int index = 0 ;
while ( true ) {
index = mParsed . find ( TQRegExp ( " <a name= " ) , index ) ;
if ( index = = - 1 ) {
kdDebug ( 7119 ) < < " no anchor \n " ;
break ; // use whatever is the target, most likely index.html
}
if ( mParsed . mid ( index , 11 + anchor . length ( ) ) . lower ( ) = =
TQString ( " <a name= \" %1 \" > " ) . arg ( anchor ) )
{
index = mParsed . findRev ( " <FILENAME filename= " , index ) +
strlen ( " <FILENAME filename= \" " ) ;
TQString filename = mParsed . mid ( index , 2000 ) ;
filename = filename . left ( filename . find ( ' \" ' ) ) ;
TQString path = target . path ( ) ;
path = path . left ( path . findRev ( ' / ' ) + 1 ) + filename ;
kdDebug ( 7119 ) < < " anchor found in " < < path < < endl ;
target . setPath ( path ) ;
break ;
}
index + + ;
}
}
emitFile ( target ) ;
}
}
finished ( ) ;
}
void HelpProtocol : : emitFile ( const KURL & url )
{
infoMessage ( i18n ( " Looking up section " ) ) ;
TQString filename = url . path ( ) . mid ( url . path ( ) . findRev ( ' / ' ) + 1 ) ;
int index = mParsed . find ( TQString ( " <FILENAME filename= \" %1 \" " ) . arg ( filename ) ) ;
if ( index = = - 1 ) {
if ( filename = = " index.html " ) {
data ( fromUnicode ( mParsed ) ) ;
return ;
}
unicodeError ( i18n ( " Could not find filename %1 in %2. " ) . arg ( filename ) . arg ( url . url ( ) ) ) ;
return ;
}
TQString filedata = splitOut ( mParsed , index ) ;
replaceCharsetHeader ( filedata ) ;
data ( fromUnicode ( filedata ) ) ;
data ( TQByteArray ( ) ) ;
}
void HelpProtocol : : mimetype ( const KURL & )
{
mimeType ( " text/html " ) ;
finished ( ) ;
}
// Copied from tdeio_file to avoid redirects
# define MAX_IPC_SIZE (1024*32)
void HelpProtocol : : get_file ( const KURL & url )
{
kdDebug ( 7119 ) < < " get_file " < < url . url ( ) < < endl ;
TQCString _path ( TQFile : : encodeName ( url . path ( ) ) ) ;
struct stat buff ;
if ( : : stat ( _path . data ( ) , & buff ) = = - 1 ) {
if ( errno = = EACCES )
error ( TDEIO : : ERR_ACCESS_DENIED , url . path ( ) ) ;
else
error ( TDEIO : : ERR_DOES_NOT_EXIST , url . path ( ) ) ;
return ;
}
if ( S_ISDIR ( buff . st_mode ) ) {
error ( TDEIO : : ERR_IS_DIRECTORY , url . path ( ) ) ;
return ;
}
if ( S_ISFIFO ( buff . st_mode ) | | S_ISSOCK ( buff . st_mode ) ) {
error ( TDEIO : : ERR_CANNOT_OPEN_FOR_READING , url . path ( ) ) ;
return ;
}
int fd = open ( _path . data ( ) , O_RDONLY ) ;
if ( fd < 0 ) {
error ( TDEIO : : ERR_CANNOT_OPEN_FOR_READING , url . path ( ) ) ;
return ;
}
totalSize ( buff . st_size ) ;
int processed_size = 0 ;
char buffer [ MAX_IPC_SIZE ] ;
TQByteArray array ;
while ( 1 )
{
int n = : : read ( fd , buffer , MAX_IPC_SIZE ) ;
if ( n = = - 1 )
{
if ( errno = = EINTR )
continue ;
error ( TDEIO : : ERR_COULD_NOT_READ , url . path ( ) ) ;
close ( fd ) ;
return ;
}
if ( n = = 0 )
break ; // Finished
array . setRawData ( buffer , n ) ;
data ( array ) ;
array . resetRawData ( buffer , n ) ;
processed_size + = n ;
processedSize ( processed_size ) ;
}
data ( TQByteArray ( ) ) ;
close ( fd ) ;
processedSize ( buff . st_size ) ;
finished ( ) ;
}