You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kchmviewer/lib/kio-msits/msits.cpp

321 lines
8.2 KiB

/***************************************************************************
* Copyright (C) 2004-2007 by Georgy Yunaev, gyunaev@ulduzsoft.com *
* Please do not use email address above for bug reports; see *
* the README file *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kinstance.h>
#include <kurl.h>
#include <kmimemagic.h>
#include <tqfile.h>
#include <tqbitarray.h>
#include <tqvaluevector.h>
#include "msits.h"
#include "libchmurlfactory.h"
using namespace KIO;
extern "C"
{
int kdemain( int argc, char **argv )
{
kdDebug() << "*** kio_msits Init" << endl;
KInstance instance( "kio_msits" );
if ( argc != 4 )
{
kdDebug() << "Usage: kio_msits protocol domain-socket1 domain-socket2" << endl;
exit (-1);
}
ProtocolMSITS slave ( argv[2], argv[3] );
slave.dispatchLoop();
kdDebug() << "*** kio_msits Done" << endl;
return 0;
}
}
ProtocolMSITS::ProtocolMSITS (const TQCString &pool_socket, const TQCString &app_socket)
: SlaveBase ("kio_msits", pool_socket, app_socket)
{
m_chmFile = 0;
}
ProtocolMSITS::~ProtocolMSITS()
{
if ( !m_chmFile )
return;
chm_close (m_chmFile);
m_chmFile = 0;
}
// A simple stat() wrapper
static bool isDirectory ( const TQString & filename )
{
return filename[filename.length() - 1] == '/';
}
void ProtocolMSITS::get( const KURL& url )
{
TQString htmdata, fileName;
chmUnitInfo ui;
TQByteArray buf;
kdDebug() << "kio_msits::get() " << url.path() << endl;
if ( !parseLoadAndLookup ( url, fileName ) )
return; // error() has been called by parseLoadAndLookup
kdDebug() << "kio_msits::get: parseLoadAndLookup returned " << fileName << endl;
if ( LCHMUrlFactory::handleFileType( url.path(), htmdata ) )
{
buf = htmdata.utf8();
kdDebug() << "Using special handling for image pages: " << htmdata << endl;
}
else
{
if ( isDirectory (fileName) )
{
error( KIO::ERR_IS_DIRECTORY, url.prettyURL() );
return;
}
if ( !ResolveObject ( fileName, &ui) )
{
kdDebug() << "kio_msits::get: could not resolve filename " << fileName << endl;
error( KIO::ERR_DOES_NOT_EXIST, url.prettyURL() );
return;
}
buf.resize( ui.length );
if ( RetrieveObject (&ui, (unsigned char*) buf.data(), 0, ui.length) == 0 )
{
kdDebug() << "kio_msits::get: could not retrieve filename " << fileName << endl;
error( KIO::ERR_NO_CONTENT, url.prettyURL() );
return;
}
}
totalSize( buf.size() );
KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( buf, fileName );
kdDebug() << "Emitting mimetype " << result->mimeType() << endl;
mimeType( result->mimeType() );
data( buf );
processedSize( buf.size() );
finished();
}
bool ProtocolMSITS::parseLoadAndLookup ( const KURL& url, TQString& abspath )
{
kdDebug() << "ProtocolMSITS::parseLoadAndLookup (const KURL&) " << url.path() << endl;
int pos = url.path().find ("::");
if ( pos == -1 )
{
error( KIO::ERR_MALFORMED_URL, url.prettyURL() );
return false;
}
TQString filename = url.path().left (pos);
abspath = url.path().mid (pos + 2); // skip ::
// Some buggy apps add ms-its:/ to the path as well
if ( abspath.startsWith( "ms-its:" ) )
abspath = abspath.mid( 7 );
kdDebug() << "ProtocolMSITS::parseLoadAndLookup: filename " << filename << ", path " << abspath << endl;
if ( filename.isEmpty() )
{
error( KIO::ERR_MALFORMED_URL, url.prettyURL() );
return false;
}
// If the file has been already loaded, nothing to do.
if ( m_chmFile && filename == m_openedFile )
return true;
kdDebug() << "Opening a new CHM file " << filename << endl;
// First try to open a temporary file
chmFile * tmpchm;
if ( (tmpchm = chm_open ( TQFile::encodeName (filename))) == 0 )
{
error( KIO::ERR_COULD_NOT_READ, url.prettyURL() );
return false;
}
// Replace an existing file by a new one
if ( m_chmFile )
chm_close (m_chmFile);
m_chmFile = tmpchm;
m_openedFile = filename;
kdDebug() << "A CHM file " << filename << " has beed opened successfully" << endl;
return true;
}
/*
* Shamelessly stolen from a KDE KIO tutorial
*/
static void app_entry(UDSEntry& e, unsigned int uds, const TQString& str)
{
UDSAtom a;
a.m_uds = uds;
a.m_str = str;
e.append(a);
}
// appends an int with the UDS-ID uds
static void app_entry(UDSEntry& e, unsigned int uds, long l)
{
UDSAtom a;
a.m_uds = uds;
a.m_long = l;
e.append(a);
}
// internal function
// fills a directory item with its name and size
static void app_dir(UDSEntry& e, const TQString & name)
{
e.clear();
app_entry(e, KIO::UDS_NAME, name);
app_entry(e, KIO::UDS_FILE_TYPE, S_IFDIR);
app_entry(e, KIO::UDS_SIZE, 1);
}
// internal function
// fills a file item with its name and size
static void app_file(UDSEntry& e, const TQString & name, size_t size)
{
e.clear();
app_entry(e, KIO::UDS_NAME, name);
app_entry(e, KIO::UDS_FILE_TYPE, S_IFREG);
app_entry(e, KIO::UDS_SIZE, size);
}
void ProtocolMSITS::stat (const KURL & url)
{
TQString fileName;
chmUnitInfo ui;
kdDebug() << "kio_msits::stat (const KURL& url) " << url.path() << endl;
if ( !parseLoadAndLookup ( url, fileName ) )
return; // error() has been called by parseLoadAndLookup
if ( !ResolveObject ( fileName, &ui ) )
{
error( KIO::ERR_DOES_NOT_EXIST, url.prettyURL() );
return;
}
kdDebug() << "kio_msits::stat: adding an entry for " << fileName << endl;
UDSEntry entry;
if ( isDirectory ( fileName ) )
app_dir(entry, fileName);
else
app_file(entry, fileName, ui.length);
statEntry (entry);
finished();
}
// A local CHMLIB enumerator
static int chmlib_enumerator (struct chmFile *, struct chmUnitInfo *ui, void *context)
{
((TQValueVector<TQString> *) context)->push_back (TQString::fromLocal8Bit (ui->path));
return CHM_ENUMERATOR_CONTINUE;
}
void ProtocolMSITS::listDir (const KURL & url)
{
TQString filepath;
kdDebug() << "kio_msits::listDir (const KURL& url) " << url.path() << endl;
if ( !parseLoadAndLookup ( url, filepath ) )
return; // error() has been called by parseLoadAndLookup
filepath += "/";
if ( !isDirectory (filepath) )
{
error(KIO::ERR_CANNOT_ENTER_DIRECTORY, url.path());
return;
}
kdDebug() << "kio_msits::listDir: enumerating directory " << filepath << endl;
TQValueVector<TQString> listing;
if ( chm_enumerate_dir ( m_chmFile,
filepath.local8Bit(),
CHM_ENUMERATE_NORMAL | CHM_ENUMERATE_FILES | CHM_ENUMERATE_DIRS,
chmlib_enumerator,
&listing ) != 1 )
{
error(KIO::ERR_CANNOT_ENTER_DIRECTORY, url.path());
return;
}
UDSEntry entry;
unsigned int striplength = filepath.length();
for ( unsigned int i = 0; i < listing.size(); i++ )
{
// Strip the direcroty name
TQString ename = listing[i].mid (striplength);
if ( isDirectory ( ename ) )
app_dir(entry, ename);
else
app_file(entry, ename, 0);
listEntry(entry, false);
}
listEntry(entry, true);
finished();
}