msits.cpp 7.05 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*  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., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#include <kapplication.h>
Albert Astals Cid's avatar
Albert Astals Cid committed
22
#include <kcomponentdata.h>
23 24
#include <kdebug.h>
#include <kurl.h>
Albert Astals Cid's avatar
compile  
Albert Astals Cid committed
25
#include <kmimetype.h>
Pino Toscano's avatar
Pino Toscano committed
26
#include <kio/udsentry.h>
27 28 29

#include <qfile.h>
#include <qbitarray.h>
Pino Toscano's avatar
Pino Toscano committed
30
#include <qvector.h>
31 32 33 34 35 36 37 38

#include "msits.h"


using namespace KIO;

extern "C"
{
39
    int KDE_EXPORT kdemain( int argc, char **argv )
40
    {
Pino Toscano's avatar
Pino Toscano committed
41
		kDebug() << "*** kio_msits Init" << endl;
42

Albert Astals Cid's avatar
Albert Astals Cid committed
43
        KComponentData instance( "kio_msits" );
44 45 46

        if ( argc != 4 )
		{
Pino Toscano's avatar
Pino Toscano committed
47
            kDebug() << "Usage: kio_msits protocol domain-socket1 domain-socket2" << endl;
48 49 50 51 52 53
            exit (-1);
        }

        ProtocolMSITS slave ( argv[2], argv[3] );
        slave.dispatchLoop();

Pino Toscano's avatar
Pino Toscano committed
54
        kDebug() << "*** kio_msits Done" << endl;
55 56 57 58
        return 0;
    }
}

Pino Toscano's avatar
Pino Toscano committed
59
ProtocolMSITS::ProtocolMSITS (const QByteArray &pool_socket, const QByteArray &app_socket)
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
	: 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 QString & filename )
{
77
    return filename.endsWith( '/' );
78 79 80
}


Pino Toscano's avatar
Pino Toscano committed
81
void ProtocolMSITS::get( const KUrl& url )
82 83 84 85
{
	QString fileName;
	chmUnitInfo ui;

Pino Toscano's avatar
Pino Toscano committed
86
    kDebug() << "kio_msits::get() " << url.path() << endl;
87 88 89 90

	if ( !parseLoadAndLookup ( url, fileName ) )
		return;	// error() has been called by parseLoadAndLookup

Pino Toscano's avatar
Pino Toscano committed
91
	kDebug() << "kio_msits::get: parseLoadAndLookup returned " << fileName << endl;
92 93 94

	if ( isDirectory (fileName) )
	{
95
		error( KIO::ERR_IS_DIRECTORY, url.prettyUrl() );
96 97 98 99 100
		return;
	}

	if ( !ResolveObject ( fileName, &ui) )
	{
Pino Toscano's avatar
Pino Toscano committed
101
		kDebug() << "kio_msits::get: could not resolve filename " << fileName << endl;
102
        error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
103 104 105
		return;
	}

Pino Toscano's avatar
Pino Toscano committed
106
    QByteArray buf (ui.length, '\0');
107 108 109

	if ( RetrieveObject (&ui, (unsigned char*) buf.data(), 0, ui.length) == 0 )
	{
Pino Toscano's avatar
Pino Toscano committed
110
		kDebug() << "kio_msits::get: could not retrieve filename " << fileName << endl;
111
        error( KIO::ERR_NO_CONTENT, url.prettyUrl() );
112 113 114 115
		return;
	}

    totalSize( ui.length );
Albert Astals Cid's avatar
compile  
Albert Astals Cid committed
116 117
    KMimeType::Ptr result = KMimeType::findByNameAndContent( fileName, buf );
    kDebug() << "Emitting mimetype " << result->name() << endl;
118

Albert Astals Cid's avatar
compile  
Albert Astals Cid committed
119
	mimeType( result->name() );
120 121 122 123 124 125 126
    data( buf );
	processedSize( ui.length );

    finished();
}


Pino Toscano's avatar
Pino Toscano committed
127
bool ProtocolMSITS::parseLoadAndLookup ( const KUrl& url, QString& abspath )
128
{
Pino Toscano's avatar
Pino Toscano committed
129
	kDebug() << "ProtocolMSITS::parseLoadAndLookup (const KUrl&) " << url.path() << endl;
130

Pino Toscano's avatar
Pino Toscano committed
131
	int pos = url.path().indexOf ("::");
132 133 134

	if ( pos == -1 )
	{
135
		error( KIO::ERR_MALFORMED_URL, url.prettyUrl() );
136 137 138 139 140 141
		return false;
	}

	QString filename = url.path().left (pos);
	abspath = url.path().mid (pos + 2); // skip ::

Pino Toscano's avatar
Pino Toscano committed
142
	kDebug() << "ProtocolMSITS::parseLoadAndLookup: filename " << filename << ", path " << abspath << endl;
143 144 145

    if ( filename.isEmpty() )
    {
146
		error( KIO::ERR_MALFORMED_URL, url.prettyUrl() );
147 148 149 150 151 152 153
        return false;
    }

	// If the file has been already loaded, nothing to do.
	if ( m_chmFile && filename == m_openedFile )
		return true;

Pino Toscano's avatar
Pino Toscano committed
154
    kDebug() << "Opening a new CHM file " << filename << endl;
155 156 157 158 159 160

	// First try to open a temporary file
	chmFile * tmpchm;

	if ( (tmpchm = chm_open ( QFile::encodeName (filename))) == 0 )
	{
161
		error( KIO::ERR_COULD_NOT_READ, url.prettyUrl() );
162 163 164 165 166 167 168 169 170 171
        return false;
	}

	// Replace an existing file by a new one
	if ( m_chmFile )
		chm_close (m_chmFile);
	
	m_chmFile = tmpchm;
	m_openedFile = filename;
    
Pino Toscano's avatar
Pino Toscano committed
172
	kDebug() << "A CHM file " << filename << " has beed opened successfully" << endl;
173 174 175 176 177 178 179 180
    return true;
}

/*
 * Shamelessly stolen from a KDE KIO tutorial
 */
static void app_entry(UDSEntry& e, unsigned int uds, const QString& str)
{
Pino Toscano's avatar
Pino Toscano committed
181
	e.insert(uds, str);
182 183 184 185 186
}

 // appends an int with the UDS-ID uds
 static void app_entry(UDSEntry& e, unsigned int uds, long l)
 {
Pino Toscano's avatar
Pino Toscano committed
187
	e.insert(uds, l);
188 189 190 191 192 193 194
}

// internal function
// fills a directory item with its name and size
static void app_dir(UDSEntry& e, const QString & name)
{
	e.clear();
Pino Toscano's avatar
Pino Toscano committed
195 196 197
	app_entry(e, KIO::UDSEntry::UDS_NAME, name);
	app_entry(e, KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
	app_entry(e, KIO::UDSEntry::UDS_SIZE, 1);
198 199 200 201 202 203 204
}

// internal function
// fills a file item with its name and size
static void app_file(UDSEntry& e, const QString & name, size_t size)
{
	e.clear();
Pino Toscano's avatar
Pino Toscano committed
205 206 207
	app_entry(e, KIO::UDSEntry::UDS_NAME, name);
	app_entry(e, KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
	app_entry(e, KIO::UDSEntry::UDS_SIZE, size);
208 209
}

Pino Toscano's avatar
Pino Toscano committed
210
void ProtocolMSITS::stat (const KUrl & url)
211 212 213 214
{
	QString fileName;
	chmUnitInfo ui;

Pino Toscano's avatar
Pino Toscano committed
215
    kDebug() << "kio_msits::stat (const KUrl& url) " << url.path() << endl;
216 217 218 219 220 221

	if ( !parseLoadAndLookup ( url, fileName ) )
		return;	// error() has been called by parseLoadAndLookup

	if ( !ResolveObject ( fileName, &ui ) )
	{
222
        error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
223 224 225
		return;
	}

Pino Toscano's avatar
Pino Toscano committed
226
	kDebug() << "kio_msits::stat: adding an entry for " << fileName << endl;
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
	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)
{
Pino Toscano's avatar
Pino Toscano committed
243
	((QVector<QString> *) context)->push_back (QString::fromLocal8Bit (ui->path));
244 245 246 247
	return CHM_ENUMERATOR_CONTINUE;
}


Pino Toscano's avatar
Pino Toscano committed
248
void ProtocolMSITS::listDir (const KUrl & url)
249 250 251
{
	QString filepath;

Pino Toscano's avatar
Pino Toscano committed
252
    kDebug() << "kio_msits::listDir (const KUrl& url) " << url.path() << endl;
253 254 255 256

	if ( !parseLoadAndLookup ( url, filepath ) )
		return;	// error() has been called by parseLoadAndLookup

Tobias Koenig's avatar
Tobias Koenig committed
257
	filepath += '/';
258 259 260 261 262 263 264

	if ( !isDirectory (filepath) )
	{
		error(KIO::ERR_CANNOT_ENTER_DIRECTORY, url.path());
		return;
	}

Pino Toscano's avatar
Pino Toscano committed
265
    kDebug() << "kio_msits::listDir: enumerating directory " << filepath << endl;
266

Pino Toscano's avatar
Pino Toscano committed
267
	QVector<QString> listing;
268 269

	if ( chm_enumerate_dir ( m_chmFile,
Pino Toscano's avatar
Pino Toscano committed
270
							filepath.toLocal8Bit(),
271 272 273 274 275 276 277 278 279 280
							CHM_ENUMERATE_NORMAL | CHM_ENUMERATE_FILES | CHM_ENUMERATE_DIRS,
							chmlib_enumerator,
							&listing ) != 1 )
	{
		error(KIO::ERR_CANNOT_ENTER_DIRECTORY, url.path());
		return;
	}

//	totalFiles(listing.size());
	UDSEntry entry;
281
	int striplength = filepath.length();
282

283
	for ( int i = 0; i < listing.size(); i++ )
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
	{
		// Strip the direcroty name
		QString 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();
}