TDE core libraries
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.

browserrun.cpp 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. /* This file is part of the KDE project
  2. *
  3. * Copyright (C) 2002 David Faure <faure@kde.org>
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License version 2, as published by the Free Software Foundation.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Library General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Library General Public License
  14. * along with this library; see the file COPYING.LIB. If not, write to
  15. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  16. * Boston, MA 02110-1301, USA.
  17. */
  18. #include "browserrun.h"
  19. #include <tdemessagebox.h>
  20. #include <tdefiledialog.h>
  21. #include <tdeio/job.h>
  22. #include <tdeio/scheduler.h>
  23. #include <tdelocale.h>
  24. #include <kprocess.h>
  25. #include <kstringhandler.h>
  26. #include <kuserprofile.h>
  27. #include <tdetempfile.h>
  28. #include <kdebug.h>
  29. #include <kstandarddirs.h>
  30. #include <assert.h>
  31. using namespace KParts;
  32. class BrowserRun::BrowserRunPrivate
  33. {
  34. public:
  35. bool m_bHideErrorDialog;
  36. TQString contentDisposition;
  37. };
  38. BrowserRun::BrowserRun( const KURL& url, const KParts::URLArgs& args,
  39. KParts::ReadOnlyPart *part, TQWidget* window,
  40. bool removeReferrer, bool trustedSource )
  41. : KRun( url, window, 0 /*mode*/, false /*is_local_file known*/, false /* no GUI */ ),
  42. m_args( args ), m_part( part ), m_window( window ),
  43. m_bRemoveReferrer( removeReferrer ), m_bTrustedSource( trustedSource )
  44. {
  45. d = new BrowserRunPrivate;
  46. d->m_bHideErrorDialog = false;
  47. }
  48. // BIC: merge with above ctor
  49. BrowserRun::BrowserRun( const KURL& url, const KParts::URLArgs& args,
  50. KParts::ReadOnlyPart *part, TQWidget* window,
  51. bool removeReferrer, bool trustedSource, bool hideErrorDialog )
  52. : KRun( url, window, 0 /*mode*/, false /*is_local_file known*/, false /* no GUI */ ),
  53. m_args( args ), m_part( part ), m_window( window ),
  54. m_bRemoveReferrer( removeReferrer ), m_bTrustedSource( trustedSource )
  55. {
  56. d = new BrowserRunPrivate;
  57. d->m_bHideErrorDialog = hideErrorDialog;
  58. }
  59. BrowserRun::~BrowserRun()
  60. {
  61. delete d;
  62. }
  63. void BrowserRun::init()
  64. {
  65. if ( d->m_bHideErrorDialog )
  66. {
  67. // ### KRun doesn't call a virtual method when it finds out that the URL
  68. // is either malformed, or points to a non-existing local file...
  69. // So we need to reimplement some of the checks, to handle m_bHideErrorDialog
  70. if ( !m_strURL.isValid() ) {
  71. redirectToError( TDEIO::ERR_MALFORMED_URL, m_strURL.url() );
  72. return;
  73. }
  74. if ( !m_bIsLocalFile && !m_bFault && m_strURL.isLocalFile() )
  75. m_bIsLocalFile = true;
  76. if ( m_bIsLocalFile ) {
  77. struct stat buff;
  78. if ( stat( TQFile::encodeName(m_strURL.path()), &buff ) == -1 )
  79. {
  80. kdDebug(1000) << "BrowserRun::init : " << m_strURL.prettyURL() << " doesn't exist." << endl;
  81. redirectToError( TDEIO::ERR_DOES_NOT_EXIST, m_strURL.path() );
  82. return;
  83. }
  84. m_mode = buff.st_mode; // while we're at it, save it for KRun::init() to use it
  85. }
  86. }
  87. KRun::init();
  88. }
  89. void BrowserRun::scanFile()
  90. {
  91. kdDebug(1000) << "BrowserRun::scanfile " << m_strURL.prettyURL() << endl;
  92. // Let's check for well-known extensions
  93. // Not when there is a query in the URL, in any case.
  94. // Optimization for http/https, findByURL doesn't trust extensions over http.
  95. if ( m_strURL.query().isEmpty() && !m_strURL.protocol().startsWith("http") )
  96. {
  97. KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
  98. assert( mime != 0L );
  99. if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
  100. {
  101. kdDebug(1000) << "Scanfile: MIME TYPE is " << mime->name() << endl;
  102. foundMimeType( mime->name() );
  103. return;
  104. }
  105. }
  106. if ( m_part )
  107. {
  108. TQString proto = m_part->url().protocol().lower();
  109. if (proto == "https" || proto == "webdavs") {
  110. m_args.metaData().insert("main_frame_request", "TRUE" );
  111. m_args.metaData().insert("ssl_was_in_use", "TRUE" );
  112. m_args.metaData().insert("ssl_activate_warnings", "TRUE" );
  113. } else if (proto == "http" || proto == "webdav") {
  114. m_args.metaData().insert("ssl_activate_warnings", "TRUE" );
  115. m_args.metaData().insert("ssl_was_in_use", "FALSE" );
  116. }
  117. // Set the PropagateHttpHeader meta-data if it has not already been set...
  118. if (!m_args.metaData().contains("PropagateHttpHeader"))
  119. m_args.metaData().insert("PropagateHttpHeader", "TRUE");
  120. }
  121. TDEIO::TransferJob *job;
  122. if ( m_args.doPost() && m_strURL.protocol().startsWith("http"))
  123. {
  124. job = TDEIO::http_post( m_strURL, m_args.postData, false );
  125. job->addMetaData( "content-type", m_args.contentType() );
  126. }
  127. else
  128. job = TDEIO::get(m_strURL, m_args.reload, false);
  129. if ( m_bRemoveReferrer )
  130. m_args.metaData().remove("referrer");
  131. job->addMetaData( m_args.metaData() );
  132. job->setWindow( m_window );
  133. connect( job, TQT_SIGNAL( result( TDEIO::Job *)),
  134. this, TQT_SLOT( slotBrowserScanFinished(TDEIO::Job *)));
  135. connect( job, TQT_SIGNAL( mimetype( TDEIO::Job *, const TQString &)),
  136. this, TQT_SLOT( slotBrowserMimetype(TDEIO::Job *, const TQString &)));
  137. m_job = job;
  138. }
  139. void BrowserRun::slotBrowserScanFinished(TDEIO::Job *job)
  140. {
  141. kdDebug(1000) << "BrowserRun::slotBrowserScanFinished" << endl;
  142. if ( job->error() == TDEIO::ERR_IS_DIRECTORY )
  143. {
  144. // It is in fact a directory. This happens when HTTP redirects to FTP.
  145. // Due to the "protocol doesn't support listing" code in BrowserRun, we
  146. // assumed it was a file.
  147. kdDebug(1000) << "It is in fact a directory!" << endl;
  148. // Update our URL in case of a redirection
  149. m_strURL = static_cast<TDEIO::TransferJob *>(job)->url();
  150. m_job = 0;
  151. foundMimeType( "inode/directory" );
  152. }
  153. else
  154. {
  155. if ( job->error() )
  156. handleError( job );
  157. else
  158. KRun::slotScanFinished(job);
  159. }
  160. }
  161. void BrowserRun::slotBrowserMimetype( TDEIO::Job *_job, const TQString &type )
  162. {
  163. Q_ASSERT( _job == m_job );
  164. TDEIO::TransferJob *job = static_cast<TDEIO::TransferJob *>(m_job);
  165. // Update our URL in case of a redirection
  166. //kdDebug(1000) << "old URL=" << m_strURL.url() << endl;
  167. //kdDebug(1000) << "new URL=" << job->url().url() << endl;
  168. m_strURL = job->url();
  169. kdDebug(1000) << "slotBrowserMimetype: found " << type << " for " << m_strURL.prettyURL() << endl;
  170. m_suggestedFilename = job->queryMetaData("content-disposition-filename");
  171. d->contentDisposition = job->queryMetaData("content-disposition-type");
  172. //kdDebug(1000) << "m_suggestedFilename=" << m_suggestedFilename << endl;
  173. // Make a copy to avoid a dead reference
  174. TQString _type = type;
  175. job->putOnHold();
  176. m_job = 0;
  177. KRun::setSuggestedFileName(m_suggestedFilename);
  178. foundMimeType( _type );
  179. }
  180. BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable( const TQString& _mimeType )
  181. {
  182. TQString mimeType( _mimeType );
  183. Q_ASSERT( !m_bFinished ); // only come here if the mimetype couldn't be embedded
  184. // Support for saving remote files.
  185. if ( mimeType != "inode/directory" && // dirs can't be saved
  186. !m_strURL.isLocalFile() )
  187. {
  188. if ( isTextExecutable(mimeType) )
  189. mimeType = TQString::fromLatin1("text/plain"); // view, don't execute
  190. kdDebug(1000) << "BrowserRun: ask for saving" << endl;
  191. KService::Ptr offer = KServiceTypeProfile::preferredService(mimeType, "Application");
  192. // ... -> ask whether to save
  193. KParts::BrowserRun::AskSaveResult res = askSave( m_strURL, offer, mimeType, m_suggestedFilename );
  194. if ( res == KParts::BrowserRun::Save ) {
  195. save( m_strURL, m_suggestedFilename );
  196. kdDebug(1000) << "BrowserRun::handleNonEmbeddable: Save: returning Handled" << endl;
  197. m_bFinished = true;
  198. return Handled;
  199. }
  200. else if ( res == KParts::BrowserRun::Cancel ) {
  201. // saving done or canceled
  202. kdDebug(1000) << "BrowserRun::handleNonEmbeddable: Cancel: returning Handled" << endl;
  203. m_bFinished = true;
  204. return Handled;
  205. }
  206. else // "Open" chosen (done by KRun::foundMimeType, called when returning NotHandled)
  207. {
  208. // If we were in a POST, we can't just pass a URL to an external application.
  209. // We must save the data to a tempfile first.
  210. if ( m_args.doPost() )
  211. {
  212. kdDebug(1000) << "BrowserRun: request comes from a POST, can't pass a URL to another app, need to save" << endl;
  213. m_sMimeType = mimeType;
  214. TQString extension;
  215. TQString fileName = m_suggestedFilename.isEmpty() ? m_strURL.fileName() : m_suggestedFilename;
  216. int extensionPos = fileName.findRev( '.' );
  217. if ( extensionPos != -1 )
  218. extension = fileName.mid( extensionPos ); // keep the '.'
  219. KTempFile tempFile( TQString::null, extension );
  220. KURL destURL;
  221. destURL.setPath( tempFile.name() );
  222. TDEIO::Job *job = TDEIO::file_copy( m_strURL, destURL, 0600, true /*overwrite*/, false /*no resume*/, true /*progress info*/ );
  223. job->setWindow (m_window);
  224. connect( job, TQT_SIGNAL( result( TDEIO::Job *)),
  225. this, TQT_SLOT( slotCopyToTempFileResult(TDEIO::Job *)) );
  226. return Delayed; // We'll continue after the job has finished
  227. }
  228. }
  229. }
  230. // Check if running is allowed
  231. if ( !m_bTrustedSource && // ... and untrusted source...
  232. !allowExecution( mimeType, m_strURL ) ) // ...and the user said no (for executables etc.)
  233. {
  234. m_bFinished = true;
  235. return Handled;
  236. }
  237. TDEIO::SimpleJob::removeOnHold(); // Kill any slave that was put on hold.
  238. return NotHandled;
  239. }
  240. //static
  241. bool BrowserRun::allowExecution( const TQString &serviceType, const KURL &url )
  242. {
  243. if ( !isExecutable( serviceType ) )
  244. return true;
  245. if ( !url.isLocalFile() ) // Don't permit to execute remote files
  246. return false;
  247. return ( KMessageBox::warningContinueCancel( 0, i18n( "Do you really want to execute '%1'? " ).arg( url.prettyURL() ),
  248. i18n("Execute File?"), i18n("Execute") ) == KMessageBox::Continue );
  249. }
  250. static TQString makeQuestion( const KURL& url, const TQString& mimeType, const TQString& suggestedFilename )
  251. {
  252. TQString surl = KStringHandler::csqueeze( url.prettyURL() );
  253. KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
  254. TQString comment = mimeType;
  255. // Test if the mimeType is not recognize as octet-stream.
  256. // If so then keep mime-type as comment
  257. if (mime->name() != KMimeType::defaultMimeType()) {
  258. // The mime-type is known so display the comment instead of mime-type
  259. comment = mime->comment();
  260. }
  261. // The strange order in the i18n() calls below is due to the possibility
  262. // of surl containing a '%'
  263. if ( suggestedFilename.isEmpty() )
  264. return i18n("Open '%2'?\nType: %1").arg(comment, surl);
  265. else
  266. return i18n("Open '%3'?\nName: %2\nType: %1").arg(comment, suggestedFilename, surl);
  267. }
  268. //static
  269. BrowserRun::AskSaveResult BrowserRun::askSave( const KURL & url, KService::Ptr offer, const TQString& mimeType, const TQString & suggestedFilename )
  270. {
  271. // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
  272. // NOTE: Keep this function in sync with tdebase/kcontrol/filetypes/filetypedetails.cpp
  273. // FileTypeDetails::updateAskSave()
  274. TQString question = makeQuestion( url, mimeType, suggestedFilename );
  275. // Text used for the open button
  276. TQString openText = (offer && !offer->name().isEmpty())
  277. ? i18n("&Open with '%1'").arg(offer->name())
  278. : i18n("&Open With...");
  279. int choice = KMessageBox::questionYesNoCancel(
  280. 0L, question, url.host(),
  281. KStdGuiItem::saveAs(), openText,
  282. TQString::fromLatin1("askSave")+ mimeType ); // dontAskAgainName, KEEP IN SYNC!!!
  283. return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel );
  284. // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
  285. }
  286. //static
  287. BrowserRun::AskSaveResult BrowserRun::askEmbedOrSave( const KURL & url, const TQString& mimeType, const TQString & suggestedFilename, int flags )
  288. {
  289. // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
  290. // NOTE: Keep this funcion in sync with tdebase/kcontrol/filetypes/filetypedetails.cpp
  291. // FileTypeDetails::updateAskSave()
  292. KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
  293. // Don't ask for:
  294. // - html (even new tabs would ask, due to about:blank!)
  295. // - dirs obviously (though not common over HTTP :),
  296. // - images (reasoning: no need to save, most of the time, because fast to see)
  297. // e.g. postscript is different, because takes longer to read, so
  298. // it's more likely that the user might want to save it.
  299. // - multipart/* ("server push", see tdemultipart)
  300. // - other strange 'internal' mimetypes like print/manager...
  301. // KEEP IN SYNC!!!
  302. if (flags != (int)AttachmentDisposition && (
  303. mime->is( "text/html" ) ||
  304. mime->is( "text/xml" ) ||
  305. mime->is( "inode/directory" ) ||
  306. mimeType.startsWith( "image" ) ||
  307. mime->is( "multipart/x-mixed-replace" ) ||
  308. mime->is( "multipart/replace" ) ||
  309. mimeType.startsWith( "print" ) ) )
  310. return Open;
  311. TQString question = makeQuestion( url, mimeType, suggestedFilename );
  312. int choice = KMessageBox::questionYesNoCancel(
  313. 0L, question, url.host(),
  314. KStdGuiItem::saveAs(), KGuiItem( i18n( "&Open" ), "document-open"),
  315. TQString::fromLatin1("askEmbedOrSave")+ mimeType ); // dontAskAgainName, KEEP IN SYNC!!!
  316. return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel );
  317. // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
  318. }
  319. // Default implementation, overridden in TDEHTMLRun
  320. void BrowserRun::save( const KURL & url, const TQString & suggestedFilename )
  321. {
  322. simpleSave( url, suggestedFilename, m_window );
  323. }
  324. // static
  325. void BrowserRun::simpleSave( const KURL & url, const TQString & suggestedFilename )
  326. {
  327. simpleSave (url, suggestedFilename, 0);
  328. }
  329. void BrowserRun::simpleSave( const KURL & url, const TQString & suggestedFilename,
  330. TQWidget* window )
  331. {
  332. // DownloadManager <-> konqueror integration
  333. // find if the integration is enabled
  334. // the empty key means no integration
  335. // only use the downloadmanager for non-local urls
  336. if ( !url.isLocalFile() )
  337. {
  338. TDEConfig cfg("konquerorrc", false, false);
  339. cfg.setGroup("HTML Settings");
  340. TQString downloadManger = cfg.readPathEntry("DownloadManager");
  341. if (!downloadManger.isEmpty())
  342. {
  343. // then find the download manager location
  344. kdDebug(1000) << "Using: "<<downloadManger <<" as Download Manager" <<endl;
  345. TQString cmd=TDEStandardDirs::findExe(downloadManger);
  346. if (cmd.isEmpty())
  347. {
  348. TQString errMsg=i18n("The Download Manager (%1) could not be found in your $PATH ").arg(downloadManger);
  349. TQString errMsgEx= i18n("Try to reinstall it \n\nThe integration with Konqueror will be disabled!");
  350. KMessageBox::detailedSorry(0,errMsg,errMsgEx);
  351. cfg.writePathEntry("DownloadManager",TQString::null);
  352. cfg.sync ();
  353. }
  354. else
  355. {
  356. // ### suggestedFilename not taken into account. Fix this (and
  357. // the duplicated code) with shiny new KDownload class for 3.2 (pfeiffer)
  358. // Until the shiny new class comes about, send the suggestedFilename
  359. // along with the actual URL to download. (DA)
  360. cmd += " " + TDEProcess::quote(url.url());
  361. if ( !suggestedFilename.isEmpty() )
  362. cmd +=" " + TDEProcess::quote(suggestedFilename);
  363. kdDebug(1000) << "Calling command " << cmd << endl;
  364. // slave is already on hold (slotBrowserMimetype())
  365. TDEIO::Scheduler::publishSlaveOnHold();
  366. KRun::runCommand(cmd);
  367. return;
  368. }
  369. }
  370. }
  371. // no download manager available, let's do it ourself
  372. KFileDialog *dlg = new KFileDialog( TQString::null, TQString::null /*all files*/,
  373. window , "filedialog", true );
  374. dlg->setOperationMode( KFileDialog::Saving );
  375. dlg->setCaption(i18n("Save As"));
  376. dlg->setSelection( suggestedFilename.isEmpty() ? url.fileName() : suggestedFilename );
  377. if ( dlg->exec() )
  378. {
  379. KURL destURL( dlg->selectedURL() );
  380. if ( destURL.isValid() )
  381. {
  382. TDEIO::Job *job = TDEIO::copy( url, destURL );
  383. job->setWindow (window);
  384. job->setAutoErrorHandlingEnabled( true );
  385. }
  386. }
  387. delete dlg;
  388. }
  389. void BrowserRun::slotStatResult( TDEIO::Job *job )
  390. {
  391. if ( job->error() ) {
  392. kdDebug(1000) << "BrowserRun::slotStatResult : " << job->errorString() << endl;
  393. handleError( job );
  394. } else
  395. KRun::slotStatResult( job );
  396. }
  397. void BrowserRun::handleError( TDEIO::Job * job )
  398. {
  399. if ( !job ) { // Shouldn't happen, see docu.
  400. kdWarning(1000) << "BrowserRun::handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog << endl;
  401. return;
  402. }
  403. if (d->m_bHideErrorDialog && job->error() != TDEIO::ERR_NO_CONTENT)
  404. {
  405. redirectToError( job->error(), job->errorText() );
  406. return;
  407. }
  408. // Reuse code in KRun, to benefit from d->m_showingError etc.
  409. KRun::slotStatResult( job );
  410. }
  411. void BrowserRun::redirectToError( int error, const TQString& errorText )
  412. {
  413. /**
  414. * To display this error in TDEHTMLPart instead of inside a dialog box,
  415. * we tell konq that the mimetype is text/html, and we redirect to
  416. * an error:/ URL that sends the info to tdehtml.
  417. *
  418. * The format of the error:/ URL is error:/?query#url,
  419. * where two variables are passed in the query:
  420. * error = int tdeio error code, errText = TQString error text from tdeio
  421. * The sub-url is the URL that we were trying to open.
  422. */
  423. KURL newURL(TQString("error:/?error=%1&errText=%2")
  424. .arg( error ).arg( KURL::encode_string(errorText) ), 106 );
  425. m_strURL.setPass( TQString::null ); // don't put the password in the error URL
  426. KURL::List lst;
  427. lst << newURL << m_strURL;
  428. m_strURL = KURL::join( lst );
  429. //kdDebug(1202) << "BrowserRun::handleError m_strURL=" << m_strURL.prettyURL() << endl;
  430. m_job = 0;
  431. foundMimeType( "text/html" );
  432. }
  433. void BrowserRun::slotCopyToTempFileResult(TDEIO::Job *job)
  434. {
  435. if ( job->error() ) {
  436. job->showErrorDialog( m_window );
  437. } else {
  438. // Same as KRun::foundMimeType but with a different URL
  439. (void) (KRun::runURL( static_cast<TDEIO::FileCopyJob *>(job)->destURL(), m_sMimeType ));
  440. }
  441. m_bFault = true; // see above
  442. m_bFinished = true;
  443. m_timer.start( 0, true );
  444. }
  445. bool BrowserRun::isTextExecutable( const TQString &serviceType )
  446. {
  447. return ( serviceType == "application/x-desktop" ||
  448. serviceType == "media/builtin-mydocuments" ||
  449. serviceType == "media/builtin-mycomputer" ||
  450. serviceType == "media/builtin-mynetworkplaces" ||
  451. serviceType == "media/builtin-printers" ||
  452. serviceType == "media/builtin-trash" ||
  453. serviceType == "media/builtin-webbrowser" ||
  454. serviceType == "application/x-shellscript" );
  455. }
  456. bool BrowserRun::isExecutable( const TQString &serviceType )
  457. {
  458. return KRun::isExecutable( serviceType );
  459. }
  460. bool BrowserRun::hideErrorDialog() const
  461. {
  462. return d->m_bHideErrorDialog;
  463. }
  464. TQString BrowserRun::contentDisposition() const {
  465. return d->contentDisposition;
  466. }
  467. #include "browserrun.moc"