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

KDocTools

  • sources
  • kde-4.12
  • kdelibs
  • kdoctools
kio_help.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
3  Copyright (C) 2001 Stephan Kulow <coolo@kde.org>
4  Copyright (C) 2003 Cornelius Schumacher <schumacher@kde.org>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later versio
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 
23 #include <config.h>
24 
25 #include "kio_help.h"
26 #include "xslt.h"
27 #include "xslt_help.h"
28 
29 #include <kdebug.h>
30 #include <kde_file.h>
31 #include <kurl.h>
32 #include <kglobal.h>
33 #include <klocale.h>
34 #include <kstandarddirs.h>
35 #include <kcomponentdata.h>
36 
37 #include <QtCore/QDir>
38 #include <QtCore/QFileInfo>
39 #include <QtCore/QFile>
40 #include <QtCore/QRegExp>
41 #include <QtCore/QTextCodec>
42 #include <QtGui/QTextDocument>
43 
44 
45 #ifdef HAVE_SYS_TYPES_H
46 # include <sys/types.h>
47 #endif
48 #ifdef HAVE_SYS_STAT_H
49 # include <sys/stat.h>
50 #endif
51 
52 #include <errno.h>
53 #include <fcntl.h>
54 #ifdef HAVE_STDIO_H
55 # include <stdio.h>
56 #endif
57 #ifdef HAVE_STDLIB_H
58 # include <stdlib.h>
59 #endif
60 
61 #include <libxslt/xsltutils.h>
62 #include <libxslt/transform.h>
63 
64 using namespace KIO;
65 
66 QString HelpProtocol::langLookup(const QString &fname)
67 {
68  QStringList search;
69 
70  // assemble the local search paths
71  const QStringList localDoc = KGlobal::dirs()->resourceDirs("html");
72 
73  QStringList langs = KGlobal::locale()->languageList();
74  langs.append( "en" );
75  langs.removeAll( "C" );
76 
77  // this is kind of compat hack as we install our docs in en/ but the
78  // default language is en_US
79  for (QStringList::Iterator it = langs.begin(); it != langs.end(); ++it)
80  if ( *it == "en_US" )
81  *it = "en";
82 
83  // look up the different languages
84  int ldCount = localDoc.count();
85  for (int id=0; id < ldCount; id++)
86  {
87  QStringList::ConstIterator lang;
88  for (lang = langs.constBegin(); lang != langs.constEnd(); ++lang)
89  search.append(QString("%1%2/%3").arg(localDoc[id], *lang, fname));
90  }
91 
92  // try to locate the file
93  for (QStringList::ConstIterator it = search.constBegin(); it != search.constEnd(); ++it)
94  {
95  kDebug( 7119 ) << "Looking for help in: " << *it;
96 
97  QFileInfo info(*it);
98  if (info.exists() && info.isFile() && info.isReadable())
99  return *it;
100 
101  if ( ( *it ).endsWith( QLatin1String(".html") ) )
102  {
103  QString file = (*it).left((*it).lastIndexOf('/')) + "/index.docbook";
104  kDebug( 7119 ) << "Looking for help in: " << file;
105  info.setFile(file);
106  if (info.exists() && info.isFile() && info.isReadable())
107  return *it;
108  }
109  }
110 
111 
112  return QString();
113 }
114 
115 
116 QString HelpProtocol::lookupFile(const QString &fname,
117  const QString &query, bool &redirect)
118 {
119  redirect = false;
120 
121  const QString path = fname;
122 
123  QString result = langLookup(path);
124  if (result.isEmpty())
125  {
126  result = langLookup(path+"/index.html");
127  if (!result.isEmpty())
128  {
129  KUrl red( "help:/" );
130  red.setPath( path + "/index.html" );
131  red.setQuery( query );
132  redirection(red);
133  kDebug( 7119 ) << "redirect to " << red.url();
134  redirect = true;
135  }
136  else
137  {
138  const QString documentationNotFound = "khelpcenter/documentationnotfound/index.html";
139  if (!langLookup(documentationNotFound).isEmpty())
140  {
141  KUrl red;
142  red.setProtocol("help");
143  red.setPath(documentationNotFound);
144  red.setQuery(query);
145  redirection(red);
146  redirect = true;
147  }
148  else
149  {
150  unicodeError( i18n("There is no documentation available for %1." , Qt::escape(path)) );
151  return QString();
152  }
153  }
154  } else
155  kDebug( 7119 ) << "result " << result;
156 
157  return result;
158 }
159 
160 
161 void HelpProtocol::unicodeError( const QString &t )
162 {
163 #ifdef Q_WS_WIN
164  QString encoding = "UTF-8";
165 #else
166  QString encoding = QTextCodec::codecForLocale()->name();
167 #endif
168  data(fromUnicode( QString(
169  "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\"></head>\n"
170  "%2</html>" ).arg( encoding, Qt::escape(t) ) ) );
171 
172 }
173 
174 HelpProtocol *slave = 0;
175 
176 HelpProtocol::HelpProtocol( bool ghelp, const QByteArray &pool, const QByteArray &app )
177  : SlaveBase( ghelp ? "ghelp" : "help", pool, app ), mGhelp( ghelp )
178 {
179  slave = this;
180 }
181 
182 void HelpProtocol::get( const KUrl& url )
183 {
184  kDebug( 7119 ) << "path=" << url.path()
185  << "query=" << url.query();
186 
187  bool redirect;
188  QString doc = QDir::cleanPath(url.path());
189  if (doc.contains("..")) {
190  error( KIO::ERR_DOES_NOT_EXIST, url.url() );
191  return;
192  }
193 
194  if ( !mGhelp ) {
195  if (!doc.startsWith('/'))
196  doc = doc.prepend(QLatin1Char('/'));
197 
198  if (doc.endsWith('/'))
199  doc += "index.html";
200  }
201 
202  infoMessage(i18n("Looking up correct file"));
203 
204  if ( !mGhelp ) {
205  doc = lookupFile(doc, url.query(), redirect);
206 
207  if (redirect)
208  {
209  finished();
210  return;
211  }
212  }
213 
214  if (doc.isEmpty())
215  {
216  error( KIO::ERR_DOES_NOT_EXIST, url.url() );
217  return;
218  }
219 
220  mimeType("text/html");
221  KUrl target;
222  target.setPath(doc);
223  if (url.hasHTMLRef())
224  target.setHTMLRef(url.htmlRef());
225 
226  kDebug( 7119 ) << "target " << target.url();
227 
228  QString file = target.scheme() == "file" ? target.toLocalFile() : target.path();
229 
230  if ( mGhelp ) {
231  if ( !file.endsWith( QLatin1String( ".xml" ) ) ) {
232  get_file( target );
233  return;
234  }
235  } else {
236  QString docbook_file = file.left(file.lastIndexOf('/')) + "/index.docbook";
237  if (!KStandardDirs::exists(file)) {
238  file = docbook_file;
239  } else {
240  QFileInfo fi(file);
241  if (fi.isDir()) {
242  file = file + "/index.docbook";
243  } else {
244  if ( !file.endsWith( QLatin1String( ".html" ) ) || !compareTimeStamps( file, docbook_file ) ) {
245  get_file( target );
246  return;
247  } else
248  file = docbook_file;
249  }
250  }
251  }
252 
253  infoMessage(i18n("Preparing document"));
254 
255  if ( mGhelp ) {
256  QString xsl = "customization/kde-nochunk.xsl";
257  mParsed = transform(file, KStandardDirs::locate("dtd", xsl));
258 
259  kDebug( 7119 ) << "parsed " << mParsed.length();
260 
261  if (mParsed.isEmpty()) {
262  unicodeError( i18n( "The requested help file could not be parsed:<br />%1" , file ) );
263  } else {
264  int pos1 = mParsed.indexOf( "charset=" );
265  if ( pos1 > 0 ) {
266  int pos2 = mParsed.indexOf( '"', pos1 );
267  if ( pos2 > 0 ) {
268  mParsed.replace( pos1, pos2 - pos1, "charset=UTF-8" );
269  }
270  }
271  data( mParsed.toUtf8() );
272  }
273  } else {
274 
275  kDebug( 7119 ) << "look for cache for " << file;
276 
277  mParsed = lookForCache( file );
278 
279  kDebug( 7119 ) << "cached parsed " << mParsed.length();
280 
281  if ( mParsed.isEmpty() ) {
282  mParsed = transform(file, KStandardDirs::locate("dtd", "customization/kde-chunk.xsl"));
283  if ( !mParsed.isEmpty() ) {
284  infoMessage( i18n( "Saving to cache" ) );
285 #ifdef Q_WS_WIN
286  QFileInfo fi(file);
287  // make sure filenames do not contain the base path, otherwise
288  // accessing user data from another location invalids cached files
289  // Accessing user data under a different path is possible
290  // when using usb sticks - this may affect unix/mac systems also
291  QString cache = '/' + fi.absolutePath().remove(KStandardDirs::installPath("html"),Qt::CaseInsensitive).replace('/','_') + '_' + fi.baseName() + '.';
292 #else
293  QString cache = file.left( file.length() - 7 );
294 #endif
295  saveToCache( mParsed, KStandardDirs::locateLocal( "cache",
296  "kio_help" + cache +
297  "cache.bz2" ) );
298  }
299  } else infoMessage( i18n( "Using cached version" ) );
300 
301  kDebug( 7119 ) << "parsed " << mParsed.length();
302 
303  if (mParsed.isEmpty()) {
304  unicodeError( i18n( "The requested help file could not be parsed:<br />%1" , file ) );
305  } else {
306  QString query = url.query(), anchor;
307 
308  // if we have a query, look if it contains an anchor
309  if (!query.isEmpty())
310  if (query.startsWith(QLatin1String("?anchor="))) {
311  anchor = query.mid(8).toLower();
312 
313  KUrl redirURL(url);
314 
315  redirURL.setQuery(QString());
316  redirURL.setHTMLRef(anchor);
317  redirection(redirURL);
318  finished();
319  return;
320  }
321  if (anchor.isEmpty() && url.hasHTMLRef())
322  anchor = url.htmlRef();
323 
324  kDebug( 7119 ) << "anchor: " << anchor;
325 
326  if ( !anchor.isEmpty() )
327  {
328  int index = 0;
329  while ( true ) {
330  index = mParsed.indexOf( QRegExp( "<a name=" ), index);
331  if ( index == -1 ) {
332  kDebug( 7119 ) << "no anchor\n";
333  break; // use whatever is the target, most likely index.html
334  }
335 
336  if ( mParsed.mid( index, 11 + anchor.length() ).toLower() ==
337  QString( "<a name=\"%1\">" ).arg( anchor ) )
338  {
339  index = mParsed.lastIndexOf( "<FILENAME filename=", index ) +
340  strlen( "<FILENAME filename=\"" );
341  QString filename=mParsed.mid( index, 2000 );
342  filename = filename.left( filename.indexOf( '\"' ) );
343  QString path = target.path();
344  path = path.left( path.lastIndexOf( '/' ) + 1) + filename;
345  target.setPath( path );
346  kDebug( 7119 ) << "anchor found in " << target.url();
347  break;
348  }
349  index++;
350  }
351  }
352  emitFile( target );
353  }
354  }
355 
356  finished();
357 }
358 
359 void HelpProtocol::emitFile( const KUrl& url )
360 {
361  infoMessage(i18n("Looking up section"));
362 
363  QString filename = url.path().mid(url.path().lastIndexOf('/') + 1);
364 
365  int index = mParsed.indexOf(QString("<FILENAME filename=\"%1\"").arg(filename));
366  if (index == -1) {
367  if ( filename == "index.html" ) {
368  data( fromUnicode( mParsed ) );
369  return;
370  }
371 
372  unicodeError( i18n("Could not find filename %1 in %2.", filename, url.url() ) );
373  return;
374  }
375 
376  QString filedata = splitOut(mParsed, index);
377  replaceCharsetHeader( filedata );
378 
379  data( fromUnicode( filedata ) );
380  data( QByteArray() );
381 }
382 
383 void HelpProtocol::mimetype( const KUrl &)
384 {
385  mimeType("text/html");
386  finished();
387 }
388 
389 // Copied from kio_file to avoid redirects
390 
391 #define MAX_IPC_SIZE (1024*32)
392 
393 void HelpProtocol::get_file( const KUrl& url )
394 {
395  kDebug( 7119 ) << "get_file " << url.url();
396 
397 #ifdef Q_WS_WIN
398  QFile f( url.toLocalFile() );
399  if ( !f.exists() ) {
400  error( KIO::ERR_DOES_NOT_EXIST, url.url() );
401  return;
402  }
403  if ( !f.open(QIODevice::ReadOnly) ) {
404  error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
405  return;
406  }
407  int processed_size = 0;
408  totalSize( f.size() );
409 
410  QByteArray array;
411  array.resize(MAX_IPC_SIZE);
412 
413  while( 1 )
414  {
415  qint64 n = f.read(array.data(),array.size());
416  if (n == -1) {
417  error( KIO::ERR_COULD_NOT_READ, url.path());
418  f.close();
419  return;
420  }
421  if (n == 0)
422  break; // Finished
423 
424  data( array );
425 
426  processed_size += n;
427  processedSize( processed_size );
428  }
429 
430  data( QByteArray() );
431  f.close();
432 
433  processedSize( f.size() );
434  finished();
435 #else
436  QByteArray _path( QFile::encodeName(url.path()));
437  KDE_struct_stat buff;
438  if ( KDE_stat( _path.data(), &buff ) == -1 ) {
439  if ( errno == EACCES )
440  error( KIO::ERR_ACCESS_DENIED, url.url() );
441  else
442  error( KIO::ERR_DOES_NOT_EXIST, url.url() );
443  return;
444  }
445 
446  if ( S_ISDIR( buff.st_mode ) ) {
447  error( KIO::ERR_IS_DIRECTORY, url.path() );
448  return;
449  }
450  if ( S_ISFIFO( buff.st_mode ) || S_ISSOCK ( buff.st_mode ) ) {
451  error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
452  return;
453  }
454 
455  int fd = KDE_open( _path.data(), O_RDONLY);
456  if ( fd < 0 ) {
457  error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
458  return;
459  }
460 
461  totalSize( buff.st_size );
462  int processed_size = 0;
463 
464  char buffer[ MAX_IPC_SIZE ];
465  QByteArray array;
466 
467  while( 1 )
468  {
469  int n = ::read( fd, buffer, MAX_IPC_SIZE );
470  if (n == -1)
471  {
472  if (errno == EINTR)
473  continue;
474  error( KIO::ERR_COULD_NOT_READ, url.path());
475  ::close(fd);
476  return;
477  }
478  if (n == 0)
479  break; // Finished
480 
481  array = array.fromRawData(buffer, n);
482  data( array );
483  array = array.fromRawData(buffer, n);
484 
485  processed_size += n;
486  processedSize( processed_size );
487  }
488 
489  data( QByteArray() );
490 
491  ::close( fd );
492 
493  processedSize( buff.st_size );
494 
495  finished();
496 #endif
497 }
transform
QString transform(const QString &pat, const QString &tss, const QVector< const char * > &params)
Definition: xslt.cpp:130
i18n
QString i18n(const char *text)
compareTimeStamps
bool compareTimeStamps(const QString &older, const QString &newer)
Compares two files and returns true if.
Definition: xslt_help.cpp:102
HelpProtocol
Definition: kio_help.h:36
qint64
replaceCharsetHeader
void replaceCharsetHeader(QString &output)
Definition: xslt.cpp:321
kdebug.h
kurl.h
KUrl::hasHTMLRef
bool hasHTMLRef() const
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
slave
HelpProtocol * slave
Definition: kio_help.cpp:174
KGlobal::dirs
KStandardDirs * dirs()
KUrl::toLocalFile
QString toLocalFile(AdjustPathOption trailing=LeaveTrailingSlash) const
QString
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
klocale.h
KStandardDirs::exists
static bool exists(const QString &fullPath)
KUrl
KUrl::setQuery
void setQuery(const QString &query)
KUrl::setPath
void setPath(const QString &path)
kglobal.h
KUrl::setProtocol
void setProtocol(const QString &proto)
kio_help.h
splitOut
QString splitOut(const QString &parsed, int index)
Definition: xslt.cpp:222
KIO::ERR_COULD_NOT_READ
saveToCache
bool saveToCache(const QString &contents, const QString &filename)
Definition: xslt_kde.cpp:48
KIO::SlaveBase
xslt.h
QStringList
KIO::ERR_IS_DIRECTORY
HelpProtocol::HelpProtocol
HelpProtocol(bool ghelp, const QByteArray &pool, const QByteArray &app)
Definition: kio_help.cpp:176
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::setHTMLRef
void setHTMLRef(const QString &_ref)
KUrl::htmlRef
QString htmlRef() const
fromUnicode
QByteArray fromUnicode(const QString &data)
Definition: xslt.cpp:271
KStandardDirs::installPath
static QString installPath(const char *type)
xslt_help.h
KStandardDirs::resourceDirs
QStringList resourceDirs(const char *type) const
KIO::ERR_ACCESS_DENIED
KGlobal::locale
KLocale * locale()
HelpProtocol::mimetype
virtual void mimetype(const KUrl &url)
Definition: kio_help.cpp:383
KLocale::languageList
QStringList languageList() const
KStandardDirs::locateLocal
static QString locateLocal(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
kstandarddirs.h
HelpProtocol::get
virtual void get(const KUrl &url)
Definition: kio_help.cpp:182
KUrl::query
QString query() const
KIO::ERR_CANNOT_OPEN_FOR_READING
KUrl::url
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
KIO::ERR_DOES_NOT_EXIST
kcomponentdata.h
lookForCache
QString lookForCache(const QString &filename)
Definition: xslt_help.cpp:76
MAX_IPC_SIZE
#define MAX_IPC_SIZE
Definition: kio_help.cpp:391
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:51:03 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDocTools

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal