|
|
|
/* This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <tqcstring.h>
|
|
|
|
#include <tqbitarray.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <stack>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kinstance.h>
|
|
|
|
#include <kglobal.h>
|
|
|
|
#include <kurl.h>
|
|
|
|
#include <kmimemagic.h>
|
|
|
|
#include <ktempfile.h>
|
|
|
|
|
|
|
|
#include "chm.h"
|
|
|
|
|
|
|
|
|
|
|
|
using namespace KIO;
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
int kdemain( int argc, char **argv )
|
|
|
|
{
|
|
|
|
KInstance instance( "kio_chm" );
|
|
|
|
|
|
|
|
kdDebug() << "*** Starting kio_chm " << endl;
|
|
|
|
|
|
|
|
if (argc != 4) {
|
|
|
|
kdDebug() << "Usage: kio_chm protocol domain-socket1 domain-socket2" << endl;
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ChmProtocol slave(argv[2], argv[3]);
|
|
|
|
slave.dispatchLoop();
|
|
|
|
|
|
|
|
kdDebug() << "*** kio_chm Done" << endl;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ChmProtocol::ChmProtocol(const TQCString &pool_socket, const TQCString &app_socket)
|
|
|
|
: SlaveBase("kio_chm", pool_socket, app_socket)
|
|
|
|
{
|
|
|
|
kdDebug() << "ChmProtocol::ChmProtocol()" << endl;
|
|
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
ChmProtocol::~ChmProtocol()
|
|
|
|
{
|
|
|
|
kdDebug() << "ChmProtocol::~ChmProtocol()" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------- */
|
|
|
|
void ChmProtocol::get( const KURL& url )
|
|
|
|
{
|
|
|
|
/** When :catalog is appended to the end, a plain-text representation of the catalog
|
|
|
|
* is given out where each entry consists of four lines, an integer representing the parent
|
|
|
|
* of the node, an integer representing a node's ID, the Title of the Node, and it's hyperlink.
|
|
|
|
* When :contents is appended, all contained htm- and html-files will be printed, each in a line.
|
|
|
|
*/
|
|
|
|
kdDebug() << "kio_chm::get(const KURL& url) " << url.path() << endl;
|
|
|
|
|
|
|
|
bool catalog = false;
|
|
|
|
bool contents = false;
|
|
|
|
TQString bigpath = url.path();
|
|
|
|
|
|
|
|
if(bigpath.endsWith(":catalog")) {
|
|
|
|
catalog = true;
|
|
|
|
int len = TQString(":catalog").length();
|
|
|
|
bigpath.remove(bigpath.length() - len, len); ///strip :catalog from the end
|
|
|
|
}
|
|
|
|
|
|
|
|
if(bigpath.endsWith(":contents")) {
|
|
|
|
contents = true;
|
|
|
|
int len = TQString(":contents").length();
|
|
|
|
bigpath.remove(bigpath.length() - len, len); ///strip :catalog from the end
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString path;
|
|
|
|
if ( !checkNewFile( bigpath, path ) ) {
|
|
|
|
error( KIO::ERR_DOES_NOT_EXIST, url.prettyURL() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_dirMap.find(path) == m_dirMap.end()) {
|
|
|
|
error( KIO::ERR_DOES_NOT_EXIST, url.prettyURL() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQByteArray theData;
|
|
|
|
|
|
|
|
//init..
|
|
|
|
//added by lucida lucida@users.sf.net
|
|
|
|
TQString fname = TQString();
|
|
|
|
TQString chmpath = TQString();
|
|
|
|
KTempFile f("",".html");
|
|
|
|
fname = f.name();
|
|
|
|
TQTextStream *t = f.textStream();
|
|
|
|
TQString firstPage = TQString("");
|
|
|
|
TQString m_strIndex = TQString("");
|
|
|
|
TQString tmpstr = TQString("");
|
|
|
|
bool m_bIndex = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if(contents) {
|
|
|
|
TQString output;
|
|
|
|
KURL u = url;
|
|
|
|
|
|
|
|
ChmDirectoryMap::Iterator it;
|
|
|
|
for ( it = m_dirMap.begin(); it != m_dirMap.end(); ++it) {
|
|
|
|
u.setPath(bigpath);
|
|
|
|
u.addPath(it.key());
|
|
|
|
output += u.prettyURL() + "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
data(output.local8Bit());
|
|
|
|
processedSize(output.length());
|
|
|
|
finished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//try get some page to display, if the chm missing index
|
|
|
|
ChmDirectoryMap::Iterator it;
|
|
|
|
for ( it = m_dirMap.begin(); it != m_dirMap.end(); ++it) {
|
|
|
|
tmpstr.sprintf("%s", it.key().latin1());
|
|
|
|
if ((m_strIndex == "") &&
|
|
|
|
(tmpstr.endsWith(".htm") || tmpstr.endsWith(".html")))
|
|
|
|
m_strIndex = tmpstr;
|
|
|
|
if ((tmpstr == "/index.htm") || (tmpstr == "/index.html")) {
|
|
|
|
m_strIndex = tmpstr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_strIndex.remove(0,1);
|
|
|
|
|
|
|
|
|
|
|
|
if (path == "/" || catalog) {
|
|
|
|
bool htmlOutput = !catalog;
|
|
|
|
int offset = m_dirMap["/@contents"].offset;
|
|
|
|
int length = m_dirMap["/@contents"].length;
|
|
|
|
theData.setRawData(&m_contents[offset], length);
|
|
|
|
TQString s(theData);
|
|
|
|
TQString output;
|
|
|
|
|
|
|
|
TQRegExp object("<OBJECT type=\"text/sitemap\">(.*)</OBJECT>", false);
|
|
|
|
object.setMinimal(true);
|
|
|
|
|
|
|
|
TQRegExp nameParam("<param name=\"Name\" value=\"(.*)\">", false);
|
|
|
|
nameParam.setMinimal(true);
|
|
|
|
|
|
|
|
TQRegExp localParam("<param name=\"Local\" value=\"(.*)\">", false);
|
|
|
|
localParam.setMinimal(true);
|
|
|
|
|
|
|
|
TQRegExp mergeParam("<param name=\"Merge\" value=\"(.*)\">", false);
|
|
|
|
mergeParam.setMinimal(true);
|
|
|
|
|
|
|
|
std::stack<int> parents;
|
|
|
|
int counter = 1;
|
|
|
|
int current = 0;
|
|
|
|
int old = 0, pos = 0;
|
|
|
|
parents.push(0);
|
|
|
|
while ((pos = s.find(object, pos)) != -1) {
|
|
|
|
if(htmlOutput) output += s.mid(old, pos - old);
|
|
|
|
if(catalog) {
|
|
|
|
TQRegExp ex("<UL>|</UL>", false); ex.setMinimal(true);
|
|
|
|
TQString ms = s.mid(old, pos - old);
|
|
|
|
int pos = 0;
|
|
|
|
while( (pos = ms.find(ex, pos)) != -1) {
|
|
|
|
if(ms.mid(pos, 4) == "<UL>") {
|
|
|
|
parents.push(current);
|
|
|
|
} else{
|
|
|
|
if(parents.empty()){
|
|
|
|
}else{
|
|
|
|
current = parents.top();
|
|
|
|
parents.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pos += object.matchedLength();
|
|
|
|
old = pos;
|
|
|
|
TQString obj = object.cap(1);
|
|
|
|
TQString name, local;
|
|
|
|
if (obj.find(nameParam) != -1) {
|
|
|
|
name = nameParam.cap(1);
|
|
|
|
if (obj.find(localParam) != -1) {
|
|
|
|
local = localParam.cap(1);
|
|
|
|
//output += "<a href=\"" + local + "\">" + name + "</a>";
|
|
|
|
//added by lucida lucida@users.sf.net
|
|
|
|
if (local != "" && local != "/") {
|
|
|
|
if(!catalog) {
|
|
|
|
output += "<a target=\"browse\" href=\"" + url.url() + local + "\">" + name + "</a>";
|
|
|
|
}else{
|
|
|
|
current = counter;
|
|
|
|
++counter;
|
|
|
|
KURL u = url;
|
|
|
|
u.setPath(bigpath + local);
|
|
|
|
TQString str;
|
|
|
|
output += str.sprintf("%i\n%i\n", parents.top(), current);
|
|
|
|
output += name + "\n" + u.prettyURL() + "\n";
|
|
|
|
}
|
|
|
|
m_bIndex = 1;
|
|
|
|
if (firstPage == "") firstPage = url.url()+TQString::fromLocal8Bit(local.latin1());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if(htmlOutput) output += name;
|
|
|
|
} else {
|
|
|
|
if(htmlOutput) output += name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (obj.find(mergeParam) != -1 && htmlOutput) {
|
|
|
|
TQString link = mergeParam.cap(1);
|
|
|
|
TQString href = link.left(link.find("::"));
|
|
|
|
TQString path = m_chmFile.left(m_chmFile.findRev("/") + 1);
|
|
|
|
//output += " (<a href=\"" + path + href + "\">link</a>)";
|
|
|
|
m_bIndex = 1;
|
|
|
|
output += " (<a target=\"browse\" href=\"" + url.url() + path + href + "\">link</a>)";
|
|
|
|
if (firstPage == "") firstPage = url.url()+TQString::fromLocal8Bit(local.latin1());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(htmlOutput) output += s.mid(old);
|
|
|
|
|
|
|
|
//set left pane
|
|
|
|
//added by lucida, lucida@users.sf.net
|
|
|
|
TQString lframe = TQString("</HEAD><FRAMESET COLS=\"25%,*\">\n");
|
|
|
|
lframe += "<FRAME NAME=\"index\" src=\"file:"+ fname+"\"" + " marginwidth=\"0\"></FRAME>\n";
|
|
|
|
if (!m_bIndex) {
|
|
|
|
lframe = "</HEAD><FRAMESET>";
|
|
|
|
firstPage = url.url() + TQString::fromLocal8Bit(m_strIndex.latin1());
|
|
|
|
}
|
|
|
|
theData.resetRawData(&m_contents[offset], length);
|
|
|
|
//KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( output, path );
|
|
|
|
//kdDebug() << "Emitting mimetype " << result->mimeType() << endl;
|
|
|
|
//mimeType( result->mimeType() );
|
|
|
|
/* TQCString output1 = (TQCString)(output.latin1());
|
|
|
|
data(output1);
|
|
|
|
processedSize(output1.length());*/
|
|
|
|
|
|
|
|
//construct the frame
|
|
|
|
//added by lucida lucida@users.sf.net
|
|
|
|
TQString framestr = TQString("<HTML><HEAD>\n");
|
|
|
|
framestr += lframe;
|
|
|
|
framestr += "<FRAME NAME=\"browse\" src=\"" + firstPage + "\">\n";
|
|
|
|
framestr += "</FRAME>\n";
|
|
|
|
framestr += "</FRAMESET></HTML>";
|
|
|
|
//write index file
|
|
|
|
//added by lucida lucida@users.sf.net
|
|
|
|
*t << TQString::fromLocal8Bit(output.latin1()) << endl;
|
|
|
|
|
|
|
|
if(catalog) {
|
|
|
|
data(output.local8Bit());
|
|
|
|
processedSize(output.length());
|
|
|
|
}else{
|
|
|
|
data(framestr.local8Bit());
|
|
|
|
processedSize(framestr.length());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int offset = m_dirMap[path].offset;
|
|
|
|
int length = m_dirMap[path].length;
|
|
|
|
totalSize(length);
|
|
|
|
theData.setRawData(&m_contents[offset], length);
|
|
|
|
|
|
|
|
KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( theData, path );
|
|
|
|
kdDebug() << "Emitting mimetype " << result->mimeType() << endl;
|
|
|
|
mimeType( result->mimeType() );
|
|
|
|
data(theData);
|
|
|
|
theData.resetRawData(&m_contents[offset], length);
|
|
|
|
processedSize(length);
|
|
|
|
}
|
|
|
|
|
|
|
|
finished();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------- */
|
|
|
|
bool ChmProtocol::checkNewFile( TQString fullPath, TQString& path )
|
|
|
|
{
|
|
|
|
//kdDebug() << "ChmProtocol::checkNewFile " << fullPath << endl;
|
|
|
|
|
|
|
|
fullPath = fullPath.replace(TQRegExp("::"), "");
|
|
|
|
|
|
|
|
// Are we already looking at that file ?
|
|
|
|
if ( !m_chmFile.isEmpty() && fullPath.startsWith(m_chmFile) )
|
|
|
|
{
|
|
|
|
path = fullPath.mid(m_chmFile.length()).lower();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug() << "Need to open a new file" << endl;
|
|
|
|
|
|
|
|
m_chmFile = "";
|
|
|
|
|
|
|
|
// Find where the chm file is in the full path
|
|
|
|
int pos = 0;
|
|
|
|
TQString chmFile;
|
|
|
|
path = "";
|
|
|
|
|
|
|
|
int len = fullPath.length();
|
|
|
|
if ( len != 0 && fullPath[ len - 1 ] != '/' )
|
|
|
|
fullPath += '/';
|
|
|
|
|
|
|
|
//kdDebug() << "the full path is " << fullPath << endl;
|
|
|
|
while ( (pos=fullPath.find( '/', pos+1 )) != -1 )
|
|
|
|
{
|
|
|
|
TQString tryPath = fullPath.left( pos );
|
|
|
|
//kdDebug() << fullPath << " trying " << tryPath << endl;
|
|
|
|
struct stat statbuf;
|
|
|
|
if ( ::stat( TQFile::encodeName(tryPath), &statbuf ) == 0 && !S_ISDIR(statbuf.st_mode) )
|
|
|
|
{
|
|
|
|
chmFile = tryPath;
|
|
|
|
path = fullPath.mid( pos ).lower();
|
|
|
|
kdDebug() << "fullPath=" << fullPath << " path=" << path << endl;
|
|
|
|
len = path.length();
|
|
|
|
if ( len > 2 )
|
|
|
|
{
|
|
|
|
if ( path[ len - 1 ] == '/' )
|
|
|
|
path.truncate( len - 1 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
path = TQString::tqfromLatin1("/");
|
|
|
|
}
|
|
|
|
kdDebug() << "Found. chmFile=" << chmFile << " path=" << path << endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( chmFile.isEmpty() )
|
|
|
|
{
|
|
|
|
kdDebug() << "ChmProtocol::checkNewFile: not found" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_chmFile = chmFile;
|
|
|
|
|
|
|
|
// Open new file
|
|
|
|
//kdDebug() << "Opening Chm file on " << chmFile << endl;
|
|
|
|
return m_chm.read(chmFile, m_dirMap, m_contents);
|
|
|
|
}
|