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 setInstance( KMultiPartFactory::instance() );
00100
00101 QVBox *box = new QVBox( parentWidget, widgetName );
00102 setWidget( box );
00103
00104 m_extension = new KParts::BrowserExtension( this );
00105
00106
00107
00108 m_part = 0L;
00109 m_job = 0L;
00110 m_lineParser = new KLineParser;
00111 m_tempFile = 0L;
00112 }
00113
00114 KMultiPart::~KMultiPart()
00115 {
00116
00117
00118
00119
00120
00121
00122
00123 if ( m_part )
00124 delete static_cast<KParts::ReadOnlyPart *>( m_part );
00125 delete m_job;
00126 delete m_lineParser;
00127 delete m_tempFile;
00128 }
00129
00130 bool KMultiPart::openURL( const KURL &url )
00131 {
00132 m_url = url;
00133 m_lineParser->reset();
00134 m_bParsingHeader = true;
00135 m_bGotAnyHeader = false;
00136
00137 KParts::URLArgs args = m_extension->urlArgs();
00138
00139
00140
00141
00142
00143 m_job = KIO::get( url, args.reload, false );
00144
00145 emit started( m_job );
00146
00147 connect( m_job, SIGNAL( result( KIO::Job * ) ),
00148 this, SLOT( slotJobFinished( KIO::Job * ) ) );
00149 connect( m_job, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
00150 this, SLOT( slotData( KIO::Job *, const QByteArray & ) ) );
00151
00152 return true;
00153 }
00154
00155
00156
00157
00158 void KMultiPart::slotData( KIO::Job *job, const QByteArray &data )
00159 {
00160 if (m_boundary.isNull())
00161 {
00162 QString tmp = job->queryMetaData("media-boundary");
00163 kdDebug() << "Got Boundary from kio-http '" << tmp << "'" << endl;
00164 if ( !tmp.isEmpty() ) {
00165 m_boundary = QCString("--")+tmp.latin1();
00166 m_boundaryLength = m_boundary.length();
00167 }
00168 }
00169
00170 for ( uint i = 0; i < data.size() ; ++i )
00171 {
00172
00173 m_lineParser->addChar( data[i], !m_bParsingHeader );
00174 if ( m_lineParser->isLineComplete() )
00175 {
00176 QByteArray lineData = m_lineParser->currentLine();
00177 #ifdef DEBUG_PARSING
00178 kdDebug() << "lineData.size()=" << lineData.size() << endl;
00179 #endif
00180 QCString line( lineData.data(), lineData.size()+1 );
00181
00182
00183 int sz = line.size();
00184 if ( sz > 0 )
00185 line[sz-1] = '\0';
00186 #ifdef DEBUG_PARSING
00187 kdDebug() << "[" << m_bParsingHeader << "] line='" << line << "'" << endl;
00188 #endif
00189 if ( m_bParsingHeader )
00190 {
00191 if ( !line.isEmpty() )
00192 m_bGotAnyHeader = true;
00193 if ( m_boundary.isNull() )
00194 {
00195 if ( !line.isEmpty() ) {
00196 #ifdef DEBUG_PARSING
00197 kdDebug() << "Boundary is " << line << endl;
00198 #endif
00199 m_boundary = line;
00200 m_boundaryLength = m_boundary.length();
00201 }
00202 }
00203
00204 else if ( !qstrnicmp( line.data(), "Content-Type:", 13 ) )
00205 {
00206 Q_ASSERT( m_nextMimeType.isNull() );
00207 m_nextMimeType = QString::fromLatin1( line.data() + 14 ).stripWhiteSpace();
00208 kdDebug() << "m_nextMimeType=" << m_nextMimeType << endl;
00209 }
00210
00211 else if ( line.isEmpty() && m_bGotAnyHeader )
00212 {
00213 m_bParsingHeader = false;
00214 #ifdef DEBUG_PARSING
00215 kdDebug() << "end of headers" << endl;
00216 #endif
00217 startOfData();
00218 }
00219
00220 else if ( line == m_boundary )
00221 ;
00222 else if ( !line.isEmpty() )
00223 kdDebug() << "Ignoring header " << line << endl;
00224 } else {
00225 if ( !qstrncmp( line, m_boundary, m_boundaryLength ) )
00226 {
00227 #ifdef DEBUG_PARSING
00228 kdDebug() << "boundary found!" << endl;
00229 kdDebug() << "after it is " << line.data() + m_boundaryLength << endl;
00230 #endif
00231
00232 if ( !qstrncmp( line.data() + m_boundaryLength, "--", 2 ) )
00233 {
00234 #ifdef DEBUG_PARSING
00235 kdDebug() << "Completed!" << endl;
00236 #endif
00237 endOfData();
00238 emit completed();
00239 } else
00240 {
00241 char nextChar = *(line.data() + m_boundaryLength);
00242 #ifdef DEBUG_PARSING
00243 kdDebug() << "KMultiPart::slotData nextChar='" << nextChar << "'" << endl;
00244 #endif
00245 if ( nextChar == '\n' || nextChar == '\r' ) {
00246 endOfData();
00247 m_bParsingHeader = true;
00248 m_bGotAnyHeader = false;
00249 }
00250 else {
00251
00252 sendData( lineData );
00253 }
00254 }
00255 } else {
00256
00257 sendData( lineData );
00258 }
00259 }
00260 m_lineParser->clearLine();
00261 }
00262 }
00263 }
00264
00265 void KMultiPart::setPart( const QString& mimeType )
00266 {
00267 KXMLGUIFactory *guiFactory = factory();
00268 if ( guiFactory )
00269 guiFactory->removeClient( this );
00270 kdDebug() << "KMultiPart::setPart " << mimeType << endl;
00271 delete m_part;
00272
00273 m_part = KParts::ComponentFactory::createPartInstanceFromQuery<KParts::ReadOnlyPart>
00274 ( m_mimeType, QString::null, widget(), 0L, this, 0L );
00275 if ( !m_part ) {
00276
00277 KMessageBox::error( widget(), i18n("No handler found for %1!").arg(m_mimeType) );
00278 return;
00279 }
00280
00281 insertChildClient( m_part );
00282 m_part->widget()->show();
00283
00284 connect( m_part, SIGNAL( completed() ),
00285 this, SLOT( slotPartCompleted() ) );
00286
00287 KParts::BrowserExtension* childExtension = KParts::BrowserExtension::childObject( m_part );
00288
00289 if ( childExtension )
00290 {
00291
00292
00293
00294
00295 connect( childExtension, SIGNAL( openURLNotify() ),
00296 m_extension, SIGNAL( openURLNotify() ) );
00297
00298 connect( childExtension, SIGNAL( openURLRequestDelayed( const KURL &, const KParts::URLArgs & ) ),
00299 m_extension, SIGNAL( openURLRequest( const KURL &, const KParts::URLArgs & ) ) );
00300
00301 connect( childExtension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ),
00302 m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ) );
00303 connect( childExtension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs &, const KParts::WindowArgs &, KParts::ReadOnlyPart *& ) ),
00304 m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & , const KParts::WindowArgs &, KParts::ReadOnlyPart *&) ) );
00305
00306 connect( childExtension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ),
00307 m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ) );
00308 connect( childExtension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ),
00309 m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ) );
00310 connect( childExtension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ),
00311 m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ) );
00312 connect( childExtension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ),
00313 m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ) );
00314
00315 connect( childExtension, SIGNAL( infoMessage( const QString & ) ),
00316 m_extension, SIGNAL( infoMessage( const QString & ) ) );
00317
00318 childExtension->setBrowserInterface( m_extension->browserInterface() );
00319
00320 connect( childExtension, SIGNAL( enableAction( const char *, bool ) ),
00321 m_extension, SIGNAL( enableAction( const char *, bool ) ) );
00322 connect( childExtension, SIGNAL( setLocationBarURL( const QString& ) ),
00323 m_extension, SIGNAL( setLocationBarURL( const QString& ) ) );
00324 connect( childExtension, SIGNAL( setIconURL( const KURL& ) ),
00325 m_extension, SIGNAL( setIconURL( const KURL& ) ) );
00326 connect( childExtension, SIGNAL( loadingProgress( int ) ),
00327 m_extension, SIGNAL( loadingProgress( int ) ) );
00328 connect( childExtension, SIGNAL( speedProgress( int ) ),
00329 m_extension, SIGNAL( speedProgress( int ) ) );
00330 connect( childExtension, SIGNAL( selectionInfo( const KFileItemList& ) ),
00331 m_extension, SIGNAL( selectionInfo( const KFileItemList& ) ) );
00332 connect( childExtension, SIGNAL( selectionInfo( const QString& ) ),
00333 m_extension, SIGNAL( selectionInfo( const QString& ) ) );
00334 connect( childExtension, SIGNAL( selectionInfo( const KURL::List& ) ),
00335 m_extension, SIGNAL( selectionInfo( const KURL::List& ) ) );
00336 connect( childExtension, SIGNAL( mouseOverInfo( const KFileItem* ) ),
00337 m_extension, SIGNAL( mouseOverInfo( const KFileItem* ) ) );
00338 }
00339
00340 m_isHTMLPart = ( mimeType == "text/html" );
00341
00342
00343
00344 loadPlugins( this, m_part, m_part->instance() );
00345
00346 if ( guiFactory )
00347 guiFactory->addClient( this );
00348 }
00349
00350 void KMultiPart::startOfData()
00351 {
00352 kdDebug() << "KMultiPart::startOfData" << endl;
00353 Q_ASSERT( !m_nextMimeType.isNull() );
00354 if( m_nextMimeType.isNull() )
00355 return;
00356 if ( m_mimeType != m_nextMimeType )
00357 {
00358
00359 m_mimeType = m_nextMimeType;
00360 setPart( m_mimeType );
00361 }
00362 Q_ASSERT( m_part );
00363
00364 KParts::BrowserExtension* childExtension = KParts::BrowserExtension::childObject( m_part );
00365 if ( childExtension )
00366 childExtension->setURLArgs( m_extension->urlArgs() );
00367
00368 m_nextMimeType = QString::null;
00369 delete m_tempFile;
00370 m_tempFile = 0L;
00371 if ( m_isHTMLPart )
00372 {
00373 KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00374 htmlPart->begin( url() );
00375 }
00376 else
00377 m_tempFile = new KTempFile;
00378 }
00379
00380 void KMultiPart::sendData( const QByteArray& line )
00381 {
00382 if ( m_isHTMLPart )
00383 {
00384 KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00385 htmlPart->write( line.data(), line.size() );
00386 }
00387 else if ( m_tempFile )
00388 {
00389 m_tempFile->file()->writeBlock( line.data(), line.size() );
00390 }
00391 }
00392
00393 void KMultiPart::endOfData()
00394 {
00395 Q_ASSERT( m_part );
00396 if ( m_isHTMLPart )
00397 {
00398 KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00399 htmlPart->end();
00400 } else if ( m_tempFile )
00401 {
00402 m_tempFile->close();
00403 kdDebug() << "KMultiPart::endOfData opening " << m_tempFile->name() << endl;
00404 KURL url;
00405 url.setPath( m_tempFile->name() );
00406 (void) m_part->openURL( url );
00407 delete m_tempFile;
00408 m_tempFile = 0L;
00409 }
00410 }
00411
00412 void KMultiPart::slotPartCompleted()
00413 {
00414 if ( !m_isHTMLPart )
00415 {
00416 Q_ASSERT( m_part );
00417
00418 Q_ASSERT( m_part->url().isLocalFile() );
00419 kdDebug() << "slotPartCompleted deleting " << m_part->url().path() << endl;
00420 (void) unlink( QFile::encodeName( m_part->url().path() ) );
00421
00422 }
00423 }
00424
00425 bool KMultiPart::closeURL()
00426 {
00427 if ( m_part )
00428 return m_part->closeURL();
00429 return true;
00430 }
00431
00432 void KMultiPart::guiActivateEvent( KParts::GUIActivateEvent * )
00433 {
00434
00435
00436
00437 }
00438
00439 void KMultiPart::slotJobFinished( KIO::Job *job )
00440 {
00441 if ( job->error() )
00442 {
00443
00444 job->showErrorDialog();
00445 emit canceled( job->errorString() );
00446 }
00447 else
00448 {
00449
00450
00451
00452
00453
00454
00455 emit completed();
00456
00457
00458 }
00459 m_job = 0L;
00460 }
00461
00462 KAboutData* KMultiPart::createAboutData()
00463 {
00464 KAboutData* aboutData = new KAboutData( "kmultipart", I18N_NOOP("KMultiPart"),
00465 "0.1",
00466 I18N_NOOP( "Embeddable component for multipart/mixed" ),
00467 KAboutData::License_GPL,
00468 "(c) 2001, David Faure <david@mandrakesoft.com>");
00469 return aboutData;
00470 }
00471
00472 #if 0
00473 KMultiPartBrowserExtension::KMultiPartBrowserExtension( KMultiPart *parent, const char *name )
00474 : KParts::BrowserExtension( parent, name )
00475 {
00476 m_imgPart = parent;
00477 }
00478
00479 int KMultiPartBrowserExtension::xOffset()
00480 {
00481 return m_imgPart->doc()->view()->contentsX();
00482 }
00483
00484 int KMultiPartBrowserExtension::yOffset()
00485 {
00486 return m_imgPart->doc()->view()->contentsY();
00487 }
00488
00489 void KMultiPartBrowserExtension::print()
00490 {
00491 static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->print();
00492 }
00493
00494 void KMultiPartBrowserExtension::reparseConfiguration()
00495 {
00496 static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->reparseConfiguration();
00497 m_imgPart->doc()->setAutoloadImages( true );
00498 }
00499 #endif
00500
00501 #include "kmultipart.moc"