00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#include "kmultipart.h"
00021
00022
#include <qvbox.h>
00023
#include <kinstance.h>
00024
#include <kmimetype.h>
00025
#include <klocale.h>
00026
#include <kio/job.h>
00027
#include <qfile.h>
00028
#include <ktempfile.h>
00029
#include <kmessagebox.h>
00030
#include <kparts/componentfactory.h>
00031
#include <kparts/genericfactory.h>
00032
#include <khtml_part.h>
00033
#include <unistd.h>
00034
#include <kxmlguifactory.h>
00035
00036
typedef KParts::GenericFactory<KMultiPart> KMultiPartFactory;
00037 K_EXPORT_COMPONENT_FACTORY( libkmultipart , KMultiPartFactory )
00038
00039
00040
00041 class KLineParser
00042 {
00043
public:
00044 KLineParser() {
00045 m_lineComplete =
false;
00046 }
00047
void addChar(
char c,
bool storeNewline ) {
00048
if ( !storeNewline && c ==
'\r' )
00049
return;
00050 Q_ASSERT( !m_lineComplete );
00051
if ( storeNewline || c !=
'\n' ) {
00052
int sz = m_currentLine.size();
00053 m_currentLine.resize( sz+1, QGArray::SpeedOptim );
00054 m_currentLine[sz] = c;
00055 }
00056
if ( c ==
'\n' )
00057 m_lineComplete =
true;
00058 }
00059
bool isLineComplete()
const {
00060
return m_lineComplete;
00061 }
00062
QByteArray currentLine()
const {
00063
return m_currentLine;
00064 }
00065
void clearLine() {
00066 Q_ASSERT( m_lineComplete );
00067 reset();
00068 }
00069
void reset() {
00070 m_currentLine.resize( 0, QGArray::SpeedOptim );
00071 m_lineComplete =
false;
00072 }
00073
private:
00074
QByteArray m_currentLine;
00075
bool m_lineComplete;
00076 };
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 KMultiPart::KMultiPart(
QWidget *parentWidget,
const char *widgetName,
00096
QObject *parent,
const char *name,
const QStringList& )
00097 : KParts::ReadOnlyPart( parent,
name )
00098 {
00099 m_filter = 0L;
00100
00101 setInstance( KMultiPartFactory::instance() );
00102
00103
QVBox *box =
new QVBox( parentWidget, widgetName );
00104 setWidget( box );
00105
00106 m_extension =
new KParts::BrowserExtension(
this );
00107
00108
00109
00110 m_part = 0L;
00111 m_job = 0L;
00112 m_lineParser =
new KLineParser;
00113 m_tempFile = 0L;
00114 }
00115
00116 KMultiPart::~KMultiPart()
00117 {
00118
00119
00120
00121
00122
00123
00124
00125
if ( m_part )
00126
delete static_cast<KParts::ReadOnlyPart *>( m_part );
00127
delete m_job;
00128
delete m_lineParser;
00129
delete m_tempFile;
00130
delete m_filter;
00131 m_filter = 0L;
00132 }
00133
00134
00135
void KMultiPart::startHeader()
00136 {
00137 m_bParsingHeader =
true;
00138 m_bGotAnyHeader =
false;
00139 m_gzip =
false;
00140
00141
delete m_filter;
00142 m_filter = 0L;
00143 }
00144
00145
00146
bool KMultiPart::openURL(
const KURL &url )
00147 {
00148
m_url = url;
00149 m_lineParser->reset();
00150 startHeader();
00151
00152
KParts::URLArgs args = m_extension->
urlArgs();
00153
00154
00155
00156
00157
00158 m_job =
KIO::get( url, args.
reload,
false );
00159
00160 emit
started( m_job );
00161
00162
connect( m_job, SIGNAL( result(
KIO::Job * ) ),
00163
this, SLOT(
slotJobFinished(
KIO::Job * ) ) );
00164
connect( m_job, SIGNAL( data(
KIO::Job *,
const QByteArray & ) ),
00165
this, SLOT( slotData(
KIO::Job *,
const QByteArray & ) ) );
00166
00167
return true;
00168 }
00169
00170
00171
00172
00173
void KMultiPart::slotData(
KIO::Job *job,
const QByteArray &data )
00174 {
00175
if (m_boundary.
isNull())
00176 {
00177
QString tmp = job->
queryMetaData(
"media-boundary");
00178
kdDebug() <<
"Got Boundary from kio-http '" << tmp <<
"'" <<
endl;
00179
if ( !tmp.
isEmpty() ) {
00180 m_boundary =
QCString(
"--")+tmp.
latin1();
00181 m_boundaryLength = m_boundary.
length();
00182 }
00183 }
00184
00185
for ( uint i = 0; i < data.size() ; ++i )
00186 {
00187
00188 m_lineParser->addChar( data[i], !m_bParsingHeader );
00189
if ( m_lineParser->isLineComplete() )
00190 {
00191
QByteArray lineData = m_lineParser->currentLine();
00192
#ifdef DEBUG_PARSING
00193
kdDebug() <<
"lineData.size()=" << lineData.size() <<
endl;
00194
#endif
00195
QCString line( lineData.data(), lineData.size()+1 );
00196
00197
00198
int sz = line.size();
00199
if ( sz > 0 )
00200 line[sz-1] =
'\0';
00201
#ifdef DEBUG_PARSING
00202
kdDebug() <<
"[" << m_bParsingHeader <<
"] line='" << line <<
"'" <<
endl;
00203
#endif
00204
if ( m_bParsingHeader )
00205 {
00206
if ( !line.isEmpty() )
00207 m_bGotAnyHeader =
true;
00208
if ( m_boundary.
isNull() )
00209 {
00210
if ( !line.isEmpty() ) {
00211
#ifdef DEBUG_PARSING
00212
kdDebug() <<
"Boundary is " << line <<
endl;
00213
#endif
00214
m_boundary = line;
00215 m_boundaryLength = m_boundary.
length();
00216 }
00217 }
00218
else if ( !qstrnicmp( line.data(),
"Content-Encoding:", 17 ) )
00219 {
00220
QString encoding =
QString::fromLatin1(line.data()+17).stripWhiteSpace().lower();
00221
if (encoding ==
"gzip" || encoding ==
"x-gzip") {
00222 m_gzip =
true;
00223 }
else {
00224
kdDebug() <<
"FIXME: unhandled encoding type in KMultiPart: " << encoding <<
endl;
00225 }
00226 }
00227
00228
else if ( !qstrnicmp( line.data(),
"Content-Type:", 13 ) )
00229 {
00230 Q_ASSERT( m_nextMimeType.
isNull() );
00231 m_nextMimeType =
QString::fromLatin1( line.data() + 14 ).stripWhiteSpace();
00232
kdDebug() <<
"m_nextMimeType=" << m_nextMimeType <<
endl;
00233 }
00234
00235
else if ( line.isEmpty() && m_bGotAnyHeader )
00236 {
00237 m_bParsingHeader =
false;
00238
#ifdef DEBUG_PARSING
00239
kdDebug() <<
"end of headers" <<
endl;
00240
#endif
00241
startOfData();
00242 }
00243
00244
else if ( line == m_boundary )
00245 ;
00246
else if ( !line.isEmpty() )
00247
kdDebug() <<
"Ignoring header " << line <<
endl;
00248 }
else {
00249
if ( !qstrncmp( line, m_boundary, m_boundaryLength ) )
00250 {
00251
#ifdef DEBUG_PARSING
00252
kdDebug() <<
"boundary found!" <<
endl;
00253
kdDebug() <<
"after it is " << line.data() + m_boundaryLength <<
endl;
00254
#endif
00255
00256
if ( !qstrncmp( line.data() + m_boundaryLength,
"--", 2 ) )
00257 {
00258
#ifdef DEBUG_PARSING
00259
kdDebug() <<
"Completed!" <<
endl;
00260
#endif
00261
endOfData();
00262 emit
completed();
00263 }
else
00264 {
00265
char nextChar = *(line.data() + m_boundaryLength);
00266
#ifdef DEBUG_PARSING
00267
kdDebug() <<
"KMultiPart::slotData nextChar='" << nextChar <<
"'" <<
endl;
00268
#endif
00269
if ( nextChar ==
'\n' || nextChar ==
'\r' ) {
00270 endOfData();
00271 startHeader();
00272 }
00273
else {
00274
00275 sendData( lineData );
00276 }
00277 }
00278 }
else {
00279
00280 sendData( lineData );
00281 }
00282 }
00283 m_lineParser->clearLine();
00284 }
00285 }
00286 }
00287
00288
void KMultiPart::setPart(
const QString& mimeType )
00289 {
00290
KXMLGUIFactory *guiFactory =
factory();
00291
if ( guiFactory )
00292 guiFactory->
removeClient(
this );
00293
kdDebug() <<
"KMultiPart::setPart " << mimeType <<
endl;
00294
delete m_part;
00295
00296 m_part = KParts::ComponentFactory::createPartInstanceFromQuery<KParts::ReadOnlyPart>
00297 ( m_mimeType, QString::null,
widget(), 0L,
this, 0L );
00298
if ( !m_part ) {
00299
00300
KMessageBox::error(
widget(), i18n(
"No handler found for %1!").arg(m_mimeType) );
00301
return;
00302 }
00303
00304
insertChildClient( m_part );
00305 m_part->widget()->show();
00306
00307
connect( m_part, SIGNAL(
completed() ),
00308
this, SLOT( slotPartCompleted() ) );
00309
00310
KParts::BrowserExtension* childExtension =
KParts::BrowserExtension::childObject( m_part );
00311
00312
if ( childExtension )
00313 {
00314
00315
00316
00317
00318
connect( childExtension, SIGNAL( openURLNotify() ),
00319 m_extension, SIGNAL( openURLNotify() ) );
00320
00321
connect( childExtension, SIGNAL( openURLRequestDelayed(
const KURL &,
const KParts::URLArgs & ) ),
00322 m_extension, SIGNAL( openURLRequest(
const KURL &,
const KParts::URLArgs & ) ) );
00323
00324
connect( childExtension, SIGNAL( createNewWindow(
const KURL &,
const KParts::URLArgs & ) ),
00325 m_extension, SIGNAL( createNewWindow(
const KURL &,
const KParts::URLArgs & ) ) );
00326
connect( childExtension, SIGNAL( createNewWindow(
const KURL &,
const KParts::URLArgs &,
const KParts::WindowArgs &,
KParts::ReadOnlyPart *& ) ),
00327 m_extension, SIGNAL( createNewWindow(
const KURL &,
const KParts::URLArgs & ,
const KParts::WindowArgs &,
KParts::ReadOnlyPart *&) ) );
00328
00329
00330
connect( childExtension, SIGNAL( popupMenu(
const QPoint &,
const KFileItemList & ) ),
00331 m_extension, SIGNAL( popupMenu(
const QPoint &,
const KFileItemList & ) ) );
00332
connect( childExtension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KFileItemList & ) ),
00333 m_extension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KFileItemList & ) ) );
00334
connect( childExtension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KFileItemList &,
const KParts::URLArgs &,
KParts::BrowserExtension::PopupFlags ) ),
00335 m_extension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KFileItemList &,
const KParts::URLArgs &,
KParts::BrowserExtension::PopupFlags ) ) );
00336
connect( childExtension, SIGNAL( popupMenu(
const QPoint &,
const KURL &,
const QString &, mode_t ) ),
00337 m_extension, SIGNAL( popupMenu(
const QPoint &,
const KURL &,
const QString &, mode_t ) ) );
00338
connect( childExtension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KURL &,
const QString &, mode_t ) ),
00339 m_extension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KURL &,
const QString &, mode_t ) ) );
00340
connect( childExtension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KURL &,
const KParts::URLArgs &,
KParts::BrowserExtension::PopupFlags, mode_t ) ),
00341 m_extension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KURL &,
const KParts::URLArgs &,
KParts::BrowserExtension::PopupFlags, mode_t ) ) );
00342
00343
00344
connect( childExtension, SIGNAL( infoMessage(
const QString & ) ),
00345 m_extension, SIGNAL( infoMessage(
const QString & ) ) );
00346
00347 childExtension->
setBrowserInterface( m_extension->
browserInterface() );
00348
00349
connect( childExtension, SIGNAL( enableAction(
const char *,
bool ) ),
00350 m_extension, SIGNAL( enableAction(
const char *,
bool ) ) );
00351
connect( childExtension, SIGNAL( setLocationBarURL(
const QString& ) ),
00352 m_extension, SIGNAL( setLocationBarURL(
const QString& ) ) );
00353
connect( childExtension, SIGNAL( setIconURL(
const KURL& ) ),
00354 m_extension, SIGNAL( setIconURL(
const KURL& ) ) );
00355
connect( childExtension, SIGNAL( loadingProgress(
int ) ),
00356 m_extension, SIGNAL( loadingProgress(
int ) ) );
00357
connect( childExtension, SIGNAL( speedProgress(
int ) ),
00358 m_extension, SIGNAL( speedProgress(
int ) ) );
00359
connect( childExtension, SIGNAL( selectionInfo(
const KFileItemList& ) ),
00360 m_extension, SIGNAL( selectionInfo(
const KFileItemList& ) ) );
00361
connect( childExtension, SIGNAL( selectionInfo(
const QString& ) ),
00362 m_extension, SIGNAL( selectionInfo(
const QString& ) ) );
00363
connect( childExtension, SIGNAL( selectionInfo(
const KURL::List& ) ),
00364 m_extension, SIGNAL( selectionInfo(
const KURL::List& ) ) );
00365
connect( childExtension, SIGNAL( mouseOverInfo(
const KFileItem* ) ),
00366 m_extension, SIGNAL( mouseOverInfo(
const KFileItem* ) ) );
00367
connect( childExtension, SIGNAL( moveTopLevelWidget(
int,
int ) ),
00368 m_extension, SIGNAL( moveTopLevelWidget(
int,
int ) ) );
00369
connect( childExtension, SIGNAL( resizeTopLevelWidget(
int,
int ) ),
00370 m_extension, SIGNAL( resizeTopLevelWidget(
int,
int ) ) );
00371 }
00372
00373 m_isHTMLPart = ( mimeType ==
"text/html" );
00374 m_partIsLoading =
false;
00375
00376
00377
00378
loadPlugins(
this, m_part, m_part->instance() );
00379
00380
if ( guiFactory )
00381 guiFactory->
addClient(
this );
00382 }
00383
00384
void KMultiPart::startOfData()
00385 {
00386
kdDebug() <<
"KMultiPart::startOfData" <<
endl;
00387 Q_ASSERT( !m_nextMimeType.
isNull() );
00388
if( m_nextMimeType.
isNull() )
00389
return;
00390
00391
if ( m_gzip )
00392 {
00393 m_filter =
new HTTPFilterGZip;
00394
connect( m_filter, SIGNAL( output(
const QByteArray& ) ),
this, SLOT( reallySendData(
const QByteArray& ) ) );
00395 }
00396
00397
if ( m_mimeType != m_nextMimeType )
00398 {
00399
00400 m_mimeType = m_nextMimeType;
00401 setPart( m_mimeType );
00402 }
00403 Q_ASSERT( m_part );
00404
00405
KParts::BrowserExtension* childExtension =
KParts::BrowserExtension::childObject( m_part );
00406
if ( childExtension )
00407 childExtension->
setURLArgs( m_extension->
urlArgs() );
00408
00409 m_nextMimeType = QString::null;
00410
delete m_tempFile;
00411 m_tempFile = 0L;
00412
if ( m_isHTMLPart )
00413 {
00414
KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00415 htmlPart->
begin(
url() );
00416 }
00417
else
00418 {
00419
00420 m_tempFile =
new KTempFile;
00421 }
00422 }
00423
00424
void KMultiPart::sendData(
const QByteArray& line )
00425 {
00426
if ( m_filter )
00427 {
00428 m_filter->slotInput( line );
00429 }
00430
else
00431 {
00432 reallySendData( line );
00433 }
00434 }
00435
00436
void KMultiPart::reallySendData(
const QByteArray& line )
00437 {
00438
if ( m_isHTMLPart )
00439 {
00440
KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00441 htmlPart->
write( line.data(), line.size() );
00442 }
00443
else if ( m_tempFile )
00444 {
00445 m_tempFile->
file()->writeBlock( line.data(), line.size() );
00446 }
00447 }
00448
00449
void KMultiPart::endOfData()
00450 {
00451 Q_ASSERT( m_part );
00452
if ( m_isHTMLPart )
00453 {
00454
KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00455 htmlPart->
end();
00456 }
else if ( m_tempFile )
00457 {
00458 m_tempFile->
close();
00459
if ( m_partIsLoading )
00460 {
00461
00462
00463
kdDebug() <<
"KMultiPart::endOfData part isn't ready, skipping frame" <<
endl;
00464 m_tempFile->
setAutoDelete(
true );
00465 }
00466
else
00467 {
00468
kdDebug() <<
"KMultiPart::endOfData opening " << m_tempFile->
name() <<
endl;
00469
KURL url;
00470 url.
setPath( m_tempFile->
name() );
00471 m_partIsLoading =
true;
00472 (
void) m_part->openURL( url );
00473 }
00474
delete m_tempFile;
00475 m_tempFile = 0L;
00476 }
00477 }
00478
00479
void KMultiPart::slotPartCompleted()
00480 {
00481
if ( !m_isHTMLPart )
00482 {
00483 Q_ASSERT( m_part );
00484
00485 Q_ASSERT( m_part->url().isLocalFile() );
00486
kdDebug() <<
"slotPartCompleted deleting " << m_part->url().path() <<
endl;
00487 (
void) unlink( QFile::encodeName( m_part->url().path() ) );
00488 m_partIsLoading =
false;
00489
00490 }
00491 }
00492
00493
bool KMultiPart::closeURL()
00494 {
00495
if ( m_part )
00496
return m_part->closeURL();
00497
return true;
00498 }
00499
00500
void KMultiPart::guiActivateEvent(
KParts::GUIActivateEvent * )
00501 {
00502
00503
00504
00505 }
00506
00507
void KMultiPart::slotJobFinished(
KIO::Job *job )
00508 {
00509
if ( job->
error() )
00510 {
00511
00512 job->
showErrorDialog();
00513 emit
canceled( job->
errorString() );
00514 }
00515
else
00516 {
00517
00518
00519
00520
00521
00522
00523 emit
completed();
00524
00525
00526 }
00527 m_job = 0L;
00528 }
00529
00530
KAboutData* KMultiPart::createAboutData()
00531 {
00532
KAboutData* aboutData =
new KAboutData(
"kmultipart",
I18N_NOOP(
"KMultiPart"),
00533
"0.1",
00534
I18N_NOOP(
"Embeddable component for multipart/mixed" ),
00535 KAboutData::License_GPL,
00536
"(c) 2001, David Faure <david@mandrakesoft.com>");
00537
return aboutData;
00538 }
00539
00540
#if 0
00541
KMultiPartBrowserExtension::KMultiPartBrowserExtension(
KMultiPart *parent,
const char *name )
00542 : KParts::BrowserExtension( parent,
name )
00543 {
00544 m_imgPart = parent;
00545 }
00546
00547
int KMultiPartBrowserExtension::xOffset()
00548 {
00549
return m_imgPart->doc()->view()->contentsX();
00550 }
00551
00552
int KMultiPartBrowserExtension::yOffset()
00553 {
00554
return m_imgPart->doc()->view()->contentsY();
00555 }
00556
00557
void KMultiPartBrowserExtension::print()
00558 {
00559 static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->print();
00560 }
00561
00562
void KMultiPartBrowserExtension::reparseConfiguration()
00563 {
00564 static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->reparseConfiguration();
00565 m_imgPart->doc()->setAutoloadImages(
true );
00566 }
00567
#endif
00568
00569
#include "kmultipart.moc"