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
00375
00376
00377 loadPlugins( this, m_part, m_part->instance() );
00378
00379 if ( guiFactory )
00380 guiFactory->addClient( this );
00381 }
00382
00383 void KMultiPart::startOfData()
00384 {
00385 kdDebug() << "KMultiPart::startOfData" << endl;
00386 Q_ASSERT( !m_nextMimeType.isNull() );
00387 if( m_nextMimeType.isNull() )
00388 return;
00389
00390 if ( m_gzip )
00391 {
00392 m_filter = new HTTPFilterGZip;
00393 connect( m_filter, SIGNAL( output( const QByteArray& ) ), this, SLOT( reallySendData( const QByteArray& ) ) );
00394 }
00395
00396 if ( m_mimeType != m_nextMimeType )
00397 {
00398
00399 m_mimeType = m_nextMimeType;
00400 setPart( m_mimeType );
00401 }
00402 Q_ASSERT( m_part );
00403
00404 KParts::BrowserExtension* childExtension = KParts::BrowserExtension::childObject( m_part );
00405 if ( childExtension )
00406 childExtension->setURLArgs( m_extension->urlArgs() );
00407
00408 m_nextMimeType = QString::null;
00409 delete m_tempFile;
00410 m_tempFile = 0L;
00411 if ( m_isHTMLPart )
00412 {
00413 KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00414 htmlPart->begin( url() );
00415 }
00416 else
00417 m_tempFile = new KTempFile;
00418 }
00419
00420 void KMultiPart::sendData( const QByteArray& line )
00421 {
00422 if ( m_filter )
00423 {
00424 m_filter->slotInput( line );
00425 }
00426 else
00427 {
00428 reallySendData( line );
00429 }
00430 }
00431
00432 void KMultiPart::reallySendData( const QByteArray& line )
00433 {
00434 if ( m_isHTMLPart )
00435 {
00436 KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00437 htmlPart->write( line.data(), line.size() );
00438 }
00439 else if ( m_tempFile )
00440 {
00441 m_tempFile->file()->writeBlock( line.data(), line.size() );
00442 }
00443 }
00444
00445 void KMultiPart::endOfData()
00446 {
00447 Q_ASSERT( m_part );
00448 if ( m_isHTMLPart )
00449 {
00450 KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00451 htmlPart->end();
00452 } else if ( m_tempFile )
00453 {
00454 m_tempFile->close();
00455 kdDebug() << "KMultiPart::endOfData opening " << m_tempFile->name() << endl;
00456 KURL url;
00457 url.setPath( m_tempFile->name() );
00458 (void) m_part->openURL( url );
00459 delete m_tempFile;
00460 m_tempFile = 0L;
00461 }
00462 }
00463
00464 void KMultiPart::slotPartCompleted()
00465 {
00466 if ( !m_isHTMLPart )
00467 {
00468 Q_ASSERT( m_part );
00469
00470 Q_ASSERT( m_part->url().isLocalFile() );
00471 kdDebug() << "slotPartCompleted deleting " << m_part->url().path() << endl;
00472 (void) unlink( QFile::encodeName( m_part->url().path() ) );
00473
00474 }
00475 }
00476
00477 bool KMultiPart::closeURL()
00478 {
00479 if ( m_part )
00480 return m_part->closeURL();
00481 return true;
00482 }
00483
00484 void KMultiPart::guiActivateEvent( KParts::GUIActivateEvent * )
00485 {
00486
00487
00488
00489 }
00490
00491 void KMultiPart::slotJobFinished( KIO::Job *job )
00492 {
00493 if ( job->error() )
00494 {
00495
00496 job->showErrorDialog();
00497 emit canceled( job->errorString() );
00498 }
00499 else
00500 {
00501
00502
00503
00504
00505
00506
00507 emit completed();
00508
00509
00510 }
00511 m_job = 0L;
00512 }
00513
00514 KAboutData* KMultiPart::createAboutData()
00515 {
00516 KAboutData* aboutData = new KAboutData( "kmultipart", I18N_NOOP("KMultiPart"),
00517 "0.1",
00518 I18N_NOOP( "Embeddable component for multipart/mixed" ),
00519 KAboutData::License_GPL,
00520 "(c) 2001, David Faure <david@mandrakesoft.com>");
00521 return aboutData;
00522 }
00523
00524 #if 0
00525 KMultiPartBrowserExtension::KMultiPartBrowserExtension( KMultiPart *parent, const char *name )
00526 : KParts::BrowserExtension( parent, name )
00527 {
00528 m_imgPart = parent;
00529 }
00530
00531 int KMultiPartBrowserExtension::xOffset()
00532 {
00533 return m_imgPart->doc()->view()->contentsX();
00534 }
00535
00536 int KMultiPartBrowserExtension::yOffset()
00537 {
00538 return m_imgPart->doc()->view()->contentsY();
00539 }
00540
00541 void KMultiPartBrowserExtension::print()
00542 {
00543 static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->print();
00544 }
00545
00546 void KMultiPartBrowserExtension::reparseConfiguration()
00547 {
00548 static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->reparseConfiguration();
00549 m_imgPart->doc()->setAutoloadImages( true );
00550 }
00551 #endif
00552
00553 #include "kmultipart.moc"