2 This is an encapsulation of the Netscape plugin API.
4 Copyright (c) 2000 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
5 Stefan Schimanski <1Stein@gmx.de>
6 2003-2005 George Staikos <staikos@kde.org>
7 2007, 2008 Maksim Orlovich <maksim@kde.org>
8 2006, 2007, 2008 Apple Inc.
10 2008 Sebastian Sauer <mail@dipe.org>
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include "pluginhost_xembed.h"
29 #include "pluginhost_xt.h"
31 #include "classadaptor.h"
32 #include "instanceadaptor.h"
33 #include "vieweradaptor.h"
35 #include "nsplugins_callback_interface.h"
43 #include <QApplication>
50 #include <kconfiggroup.h>
53 #include <kio/netaccess.h>
54 #include <kprotocolmanager.h>
55 #include <klibloader.h>
57 #include <kstandarddirs.h>
58 #include <ktemporaryfile.h>
63 #include <X11/Intrinsic.h>
64 #include <X11/Composite.h>
65 #include <X11/Constraint.h>
66 #include <X11/Shell.h>
67 #include <X11/StringDefs.h>
69 // provide these symbols when compiling with gcc 3.x
71 #if defined __GNUC__ && defined __GNUC_MINOR__
72 # define KDE_GNUC_PREREQ(maj, min) \
73 ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
75 # define KDE_GNUC_PREREQ(maj, min) 0
79 #if defined(__GNUC__) && KDE_GNUC_PREREQ(3,0)
80 extern "C" void* __builtin_new(size_t s
)
82 return operator new(s
);
85 extern "C" void __builtin_delete(void* p
)
90 extern "C" void* __builtin_vec_new(size_t s
)
92 return operator new[](s
);
95 extern "C" void __builtin_vec_delete(void* p
)
100 extern "C" void __pure_virtual()
106 // The NSPluginInstance is always the ndata of the instance. Sometimes, plug-ins will call an instance-specific function
107 // with a NULL instance. To workaround this, we remember the last NSPluginInstance produced with the
108 // NSPluginClass::newInstance() method. This specifically works around Flash and Shockwave which do e.g. call NPN_Useragent
109 // with a NULL instance When we call NPP_New.
110 // At the moment we do setLastPluginInstance() only if the NSPluginInstance is created. Probably it would be more logical
111 // to do that more often to prevent some wired situations where we may end with the wrong NSPluginInstance for a plugin.
112 NSPluginInstance
* NSPluginInstance::s_lastPluginInstance
= 0;
113 NSPluginInstance
* NSPluginInstance::lastPluginInstance() { return s_lastPluginInstance
; }
114 void NSPluginInstance::setLastPluginInstance(NSPluginInstance
* inst
) { s_lastPluginInstance
= inst
; }
115 static NSPluginInstance
* pluginViewForInstance(NPP instance
)
117 if (instance
&& instance
->ndata
)
118 return static_cast<NSPluginInstance
*>(instance
->ndata
);
119 return NSPluginInstance::lastPluginInstance();
122 // server side functions -----------------------------------------------------
125 void *g_NPN_MemAlloc(uint32 size
)
127 void *mem
= ::malloc(size
);
129 //kDebug(1431) << "g_NPN_MemAlloc(), size=" << size << " allocated at " << mem;
136 void g_NPN_MemFree(void *ptr
)
138 //kDebug(1431) << "g_NPN_MemFree() at " << ptr;
143 uint32
g_NPN_MemFlush(uint32 size
)
146 //kDebug(1431) << "g_NPN_MemFlush()";
147 // MAC OS only.. we don't use this
153 void g_NPN_ForceRedraw(NPP
/*instance*/)
155 // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api3.html#999401
157 kDebug(1431) << "g_NPN_ForceRedraw() [unimplemented]";
162 void g_NPN_InvalidateRect(NPP
/*instance*/, NPRect
* /*invalidRect*/)
164 // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api7.html#999503
166 kDebug(1431) << "g_NPN_InvalidateRect() [unimplemented]";
171 void g_NPN_InvalidateRegion(NPP
/*instance*/, NPRegion
/*invalidRegion*/)
173 // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api8.html#999528
175 kDebug(1431) << "g_NPN_InvalidateRegion() [unimplemented]";
180 NPError
g_NPN_GetValue(NPP
/*instance*/, NPNVariable variable
, void *value
)
182 kDebug(1431) << "g_NPN_GetValue(), variable=" << static_cast<int>(variable
);
187 *(void**)value
= QX11Info::display();
188 return NPERR_NO_ERROR
;
189 case NPNVxtAppContext
:
190 *(void**)value
= XtDisplayToApplicationContext(QX11Info::display());
191 return NPERR_NO_ERROR
;
192 case NPNVjavascriptEnabledBool
:
193 *(bool*)value
= true;
194 return NPERR_NO_ERROR
;
195 case NPNVasdEnabledBool
:
196 // SmartUpdate - we don't do this
197 *(bool*)value
= false;
198 return NPERR_NO_ERROR
;
199 case NPNVisOfflineBool
:
200 // Offline browsing - no thanks
201 *(bool*)value
= false;
202 return NPERR_NO_ERROR
;
203 case NPNVSupportsXEmbedBool
:
204 // ### may depend on event loop setting
205 *(bool*)value
= true;
206 return NPERR_NO_ERROR
;
208 // This is messy. OSS things want to see "Gtk2" here;
209 // but commercial flash works better if we return something else.
210 // So we return a KHTML classic, since we can work with
211 // the community members far easier.
212 *(NPNToolkitType
*)value
= (NPNToolkitType
)0xFEEDABEE;
213 return NPERR_NO_ERROR
;
214 case NPPVpluginKeepLibraryInMemory
:
215 *(bool*)value
= true;
216 return NPERR_NO_ERROR
;
218 kDebug(1431) << "g_NPN_GetValue(), [unimplemented] variable=" << variable
;
219 return NPERR_INVALID_PARAM
;
224 NPError
g_NPN_DestroyStream(NPP instance
, NPStream
* stream
,
227 // FIXME: is this correct? I imagine it is not. (GS)
228 kDebug(1431) << "g_NPN_DestroyStream()";
230 NSPluginInstance
*inst
= pluginViewForInstance(instance
);
231 inst
->streamFinished( (NSPluginStream
*)stream
->ndata
);
235 return NPERR_NO_ERROR
;
236 case NPRES_USER_BREAK
:
237 // FIXME: notify the user
238 case NPRES_NETWORK_ERR
:
239 // FIXME: notify the user
241 return NPERR_GENERIC_ERROR
;
246 NPError
g_NPN_RequestRead(NPStream
* /*stream*/, NPByteRange
* /*rangeList*/)
248 // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api16.html#999734
249 kDebug(1431) << "g_NPN_RequestRead() [unimplemented]";
252 return NPERR_GENERIC_ERROR
;
255 NPError
g_NPN_NewStream(NPP
/*instance*/, NPMIMEType
/*type*/,
256 const char* /*target*/, NPStream
** /*stream*/)
258 // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api12.html#999628
259 kDebug(1431) << "g_NPN_NewStream() [unimplemented]";
262 // This creates a stream from the plugin to the browser of type "type" to
263 // display in "target"
264 return NPERR_GENERIC_ERROR
;
267 int32
g_NPN_Write(NPP
/*instance*/, NPStream
* /*stream*/, int32
/*len*/, void* /*buf*/)
269 // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api21.html#999859
270 kDebug(1431) << "g_NPN_Write() [unimplemented]";
278 NPError
g_NPN_GetURL(NPP instance
, const char *url
, const char *target
)
280 kDebug(1431) << "g_NPN_GetURL: url=" << url
<< " target=" << target
;
282 NSPluginInstance
*inst
= pluginViewForInstance(instance
);
284 inst
->requestURL( QString::fromLatin1(url
), QString(),
285 QString::fromLatin1(target
), 0 );
288 return NPERR_NO_ERROR
;
292 NPError
g_NPN_GetURLNotify(NPP instance
, const char *url
, const char *target
,
295 kDebug(1431) << "g_NPN_GetURLNotify: url=" << url
<< " target=" << target
<< " inst=" << (void*)instance
;
296 NSPluginInstance
*inst
= pluginViewForInstance(instance
);
298 kDebug(1431) << "g_NPN_GetURLNotify: ndata=" << (void*)inst
;
299 inst
->requestURL( QString::fromLatin1(url
), QString(),
300 QString::fromLatin1(target
), notifyData
, true );
303 return NPERR_NO_ERROR
;
307 NPError
g_NPN_PostURLNotify(NPP instance
, const char* url
, const char* target
,
308 uint32 len
, const char* buf
, NPBool file
, void* notifyData
)
310 // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api14.html
311 kDebug(1431) << "g_NPN_PostURLNotify() [incomplete]";
312 kDebug(1431) << "url=[" << url
<< "] target=[" << target
<< "]";
314 KParts::OpenUrlArguments args
;
315 KParts::BrowserArguments browserArgs
;
318 return NPERR_NO_DATA
;
321 if (file
) { // buf is a filename
323 if (!f
.open(QIODevice::ReadOnly
)) {
324 return NPERR_FILE_NOT_FOUND
;
327 // FIXME: this will not work because we need to strip the header out!
328 postdata
= f
.readAll();
330 } else { // buf is raw data
331 // First strip out the header
332 const char *previousStart
= buf
;
334 bool previousCR
= true;
341 if (buf
[l
-1] == '\n' || (previousCR
&& buf
[l
-1] == '\r')) {
342 if (previousCR
) { // header is done!
343 if ((buf
[l
-1] == '\r' && buf
[l
] == '\n') ||
344 (buf
[l
-1] == '\n' && buf
[l
] == '\r'))
347 previousStart
= &buf
[l
-1];
351 QString thisLine
= QString::fromLatin1(previousStart
, &buf
[l
-1] - previousStart
).trimmed();
353 previousStart
= &buf
[l
];
356 kDebug(1431) << "Found header line: [" << thisLine
<< "]";
357 if (thisLine
.startsWith("Content-Type: ")) {
358 browserArgs
.setContentType(thisLine
);
365 postdata
= QByteArray(previousStart
, len
- l
+ 1);
368 kDebug(1431) << "Post data: " << postdata
.size() << " bytes";
370 QFile
f("/tmp/nspostdata");
371 f
.open(QIODevice::WriteOnly
);
376 if (!target
|| !*target
) {
377 // Send the results of the post to the plugin
378 // (works by default)
379 } else if (!strcmp(target
, "_current") || !strcmp(target
, "_self") ||
380 !strcmp(target
, "_top")) {
381 // Unload the plugin, put the results in the frame/window that the
382 // plugin was loaded in
384 } else if (!strcmp(target
, "_new") || !strcmp(target
, "_blank")){
385 // Open a new browser window and write the results there
388 // Write the results to the specified frame
392 NSPluginInstance
*inst
= pluginViewForInstance(instance
);
393 if (inst
&& !inst
->normalizedURL(QString::fromLatin1(url
)).isNull()) {
394 inst
->postURL( QString::fromLatin1(url
), postdata
, browserArgs
.contentType(),
395 QString::fromLatin1(target
), notifyData
, args
, browserArgs
, true );
397 // Unsupported / insecure
398 return NPERR_INVALID_URL
;
401 return NPERR_NO_ERROR
;
405 NPError
g_NPN_PostURL(NPP instance
, const char* url
, const char* target
,
406 uint32 len
, const char* buf
, NPBool file
)
408 // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api13.html
409 kDebug(1431) << "g_NPN_PostURL()";
410 kDebug(1431) << "url=[" << url
<< "] target=[" << target
<< "]";
412 KParts::OpenUrlArguments args
;
413 KParts::BrowserArguments browserArgs
;
416 return NPERR_NO_DATA
;
419 if (file
) { // buf is a filename
421 if (!f
.open(QIODevice::ReadOnly
)) {
422 return NPERR_FILE_NOT_FOUND
;
425 // FIXME: this will not work because we need to strip the header out!
426 postdata
= f
.readAll();
428 } else { // buf is raw data
429 // First strip out the header
430 const char *previousStart
= buf
;
432 bool previousCR
= true;
439 if (buf
[l
-1] == '\n' || (previousCR
&& buf
[l
-1] == '\r')) {
440 if (previousCR
) { // header is done!
441 if ((buf
[l
-1] == '\r' && buf
[l
] == '\n') ||
442 (buf
[l
-1] == '\n' && buf
[l
] == '\r'))
445 previousStart
= &buf
[l
-1];
449 QString thisLine
= QString::fromLatin1(previousStart
, &buf
[l
-1] - previousStart
).trimmed();
451 previousStart
= &buf
[l
];
454 kDebug(1431) << "Found header line: [" << thisLine
<< "]";
455 if (thisLine
.startsWith("Content-Type: ")) {
456 browserArgs
.setContentType(thisLine
);
463 postdata
= QByteArray(previousStart
, len
- l
+ 1);
466 kDebug(1431) << "Post data: " << postdata
.size() << " bytes";
468 QFile
f("/tmp/nspostdata");
469 f
.open(QIODevice::WriteOnly
);
474 if (!target
|| !*target
) {
475 // Send the results of the post to the plugin
476 // (works by default)
477 } else if (!strcmp(target
, "_current") || !strcmp(target
, "_self") ||
478 !strcmp(target
, "_top")) {
479 // Unload the plugin, put the results in the frame/window that the
480 // plugin was loaded in
482 } else if (!strcmp(target
, "_new") || !strcmp(target
, "_blank")){
483 // Open a new browser window and write the results there
486 // Write the results to the specified frame
490 NSPluginInstance
*inst
= pluginViewForInstance(instance
);
491 if (inst
&& !inst
->normalizedURL(QString::fromLatin1(url
)).isNull()) {
492 inst
->postURL( QString::fromLatin1(url
), postdata
, browserArgs
.contentType(),
493 QString::fromLatin1(target
), 0L, args
, browserArgs
, false );
495 // Unsupported / insecure
496 return NPERR_INVALID_URL
;
499 return NPERR_NO_ERROR
;
503 // display status message
504 void g_NPN_Status(NPP instance
, const char *message
)
506 kDebug(1431) << "g_NPN_Status(): " << message
;
511 // turn into an instance signal
512 NSPluginInstance
*inst
= pluginViewForInstance(instance
);
514 inst
->emitStatus(message
);
518 static QByteArray uaStore
;
519 static QByteArray
uaEmpty("Gecko");
521 // inquire user agent
522 const char *g_NPN_UserAgent(NPP instance
)
525 return uaEmpty
.data();
527 if (uaStore
.isEmpty()) {
528 KProtocolManager kpm
;
529 QString agent
= kpm
.userAgentForHost("nspluginviewer");
530 uaStore
= agent
.toLatin1();
533 kDebug(1431) << "g_NPN_UserAgent() = " << uaStore
;
534 return uaStore
.data();
538 // inquire version information
539 void g_NPN_Version(int *plugin_major
, int *plugin_minor
, int *browser_major
, int *browser_minor
)
541 kDebug(1431) << "g_NPN_Version()";
543 // FIXME: Use the sensible values
544 *browser_major
= NP_VERSION_MAJOR
;
545 *browser_minor
= NP_VERSION_MINOR
;
547 *plugin_major
= NP_VERSION_MAJOR
;
548 *plugin_minor
= NP_VERSION_MINOR
;
552 void g_NPN_ReloadPlugins(NPBool reloadPages
)
554 // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api15.html#999713
555 kDebug(1431) << "g_NPN_ReloadPlugins()";
556 QString prog
= KGlobal::dirs()->findExe("nspluginscan");
559 // This is the proper way, but it cannot be done because we have no
560 // handle to the caller! How stupid! We cannot force all konqi windows
561 // to reload - that would be evil.
562 //p.start(K3Process::Block);
563 // Let's only allow the caller to be reloaded, not everything.
565 // _callback->reloadPage();
566 QProcess::startDetached(prog
);
568 QProcess::startDetached(prog
);
574 JRIEnv
*g_NPN_GetJavaEnv()
576 kDebug(1431) << "g_NPN_GetJavaEnv() [unimplemented]";
577 // FIXME - what do these do? I can't find docs, and even Mozilla doesn't
583 jref
g_NPN_GetJavaPeer(NPP
/*instance*/)
585 kDebug(1431) << "g_NPN_GetJavaPeer() [unimplemented]";
586 // FIXME - what do these do? I can't find docs, and even Mozilla doesn't
592 NPError
g_NPN_SetValue(NPP
/*instance*/, NPPVariable variable
, void* /*value*/)
594 kDebug(1431) << "g_NPN_SetValue() [unimplemented]";
596 case NPPVpluginWindowBool
:
598 // If true, the plugin is windowless. If false, it is in a window.
599 case NPPVpluginTransparentBool
:
601 // If true, the plugin is displayed transparent
603 return NPERR_GENERIC_ERROR
;
610 These two are in the ABI version 16 which we don't claim to support, but
613 static void g_NPN_PushPopupsEnabledState(NPP
/*instance*/, NPBool enabled
)
615 kDebug(1431) << "[unimplemented]" << enabled
;
618 static void g_NPN_PopPopupsEnabledState(NPP
/*instance*/)
620 kDebug(1431) << "[unimplemented]";
623 /******************************************************************/
625 static int s_instanceCounter
= 0;
627 NSPluginInstance::NSPluginInstance(NPP privateData
, NPPluginFuncs
*pluginFuncs
,
629 const QString
&src
, const QString
&/*mime*/,
630 const QString
&appId
, const QString
&callbackId
,
635 // The object name is the dbus object path
636 (void) new InstanceAdaptor( this );
637 setObjectName( QString( "/Instance_" ) + QString::number( ++s_instanceCounter
) );
638 QDBusConnection::sessionBus().registerObject( objectName(), this );
646 _callback
= new org::kde::nsplugins::CallBack( appId
, callbackId
, QDBusConnection::sessionBus() );
649 base
.setFileName( QString() );
650 _baseURL
= base
.url();
652 memcpy(&_pluginFuncs
, pluginFuncs
, sizeof(_pluginFuncs
));
654 _timer
= new QTimer( this );
655 connect( _timer
, SIGNAL(timeout()), SLOT(timer()) );
657 kDebug(1431) << "NSPluginInstance::NSPluginInstance";
658 kDebug(1431) << "pdata = " << _npp
->pdata
;
659 kDebug(1431) << "ndata = " << _npp
->ndata
;
661 // Create the appropriate host for the plugin type.
663 int result
= PR_FALSE
;
665 //### iceweasel does something odd here --- it enabled XEmbed for swfdec,
666 // even though that doesn't provide GetValue at all(!)
667 if (NPGetValue(NPPVpluginNeedsXEmbed
, &result
) == NPERR_NO_ERROR
&& result
) {
668 kDebug(1431) << "plugin reqests XEmbed";
669 _pluginHost
= new PluginHostXEmbed(this);
671 kDebug(1431) << "plugin requests Xt";
672 _pluginHost
= new PluginHostXt(this);
675 XSync(QX11Info::display(), false);
678 NSPluginInstance::~NSPluginInstance()
680 kDebug(1431) << "-> ~NSPluginInstance";
682 kDebug(1431) << "<- ~NSPluginInstance";
685 void NSPluginInstance::destroy()
689 kDebug(1431) << "delete streams";
690 qDeleteAll( _waitingRequests
);
692 while ( !_streams
.isEmpty() ) {
693 NSPluginStreamBase
*s
= _streams
.takeFirst();
698 kDebug(1431) << "delete tempfiles";
699 qDeleteAll( _tempFiles
);
701 kDebug(1431) << "delete callbacks";
705 kDebug(1431) << "destroy plugin";
706 NPSavedData
*saved
= 0;
708 // As of 7/31/01, nsplugin crashes when used with Qt
709 // linked with libGL if the destroy function is called.
710 // A patch on that date hacked out the following call.
711 // On 11/17/01, Jeremy White has reenabled this destroy
712 // in a an attempt to better understand why this crash
713 // occurs so that the real problem can be found and solved.
714 // It's possible that a flaw in the SetWindow call
715 // caused the crash and it is now fixed.
716 if ( _pluginFuncs
.destroy
)
717 _pluginFuncs
.destroy( _npp
, &saved
);
719 if (saved
&& saved
->len
&& saved
->buf
)
720 g_NPN_MemFree(saved
->buf
);
722 g_NPN_MemFree(saved
);
728 ::free(_npp
); // matched with malloc() in newInstance
736 void NSPluginInstance::shutdown()
738 NSPluginClass
*cls
= dynamic_cast<NSPluginClass
*>(parent());
741 cls
->destroyInstance( this );
746 void NSPluginInstance::timer()
749 _timer
->setSingleShot( true );
750 _timer
->start( 100 );
756 // start queued requests
757 kDebug(1431) << "looking for waiting requests";
758 while ( !_waitingRequests
.isEmpty() ) {
759 kDebug(1431) << "request found";
760 Request
req( *_waitingRequests
.head() );
761 delete _waitingRequests
.dequeue();
766 if ( req
.url
.left(11).toLower()=="javascript:" )
768 else if ( KUrl::isRelativeUrl(req
.url
) ) {
770 KUrl
absUrl( bu
, req
.url
);
772 } else if ( req
.url
[0]=='/' && KUrl(_baseURL
).hasHost() ) {
773 KUrl
absUrl( _baseURL
);
774 absUrl
.setPath( req
.url
);
779 // non empty target = frame target
780 if ( !req
.target
.isEmpty())
785 _callback
->postURL( url
, req
.target
, req
.data
, req
.mime
);
787 _callback
->requestURL( url
, req
.target
);
790 NPURLNotify( req
.url
, NPRES_DONE
, req
.notify
);
796 kDebug(1431) << "Starting new stream " << req
.url
;
800 NSPluginStream
*s
= new NSPluginStream( this );
801 connect( s
, SIGNAL(finished(NSPluginStreamBase
*)),
802 SLOT(streamFinished(NSPluginStreamBase
*)) );
803 _streams
.append( s
);
805 kDebug() << "posting to " << url
;
807 emitStatus( i18n("Submitting data to %1", url
) );
808 s
->post( url
, req
.data
, req
.mime
, req
.notify
, req
.args
, req
.browserArgs
);
809 } else if (url
.toLower().startsWith("javascript:")){
811 static int _jsrequestid
= 0;
812 _jsrequests
.insert(_jsrequestid
, new Request(req
));
813 _callback
->evalJavaScript(_jsrequestid
++, url
.mid(11));
815 kDebug() << "No callback for javascript: url!";
819 NSPluginStream
*s
= new NSPluginStream( this );
820 connect( s
, SIGNAL(finished(NSPluginStreamBase
*)),
821 SLOT(streamFinished(NSPluginStreamBase
*)) );
822 _streams
.append( s
);
824 kDebug() << "getting " << url
;
826 emitStatus( i18n("Requesting %1", url
) );
827 s
->get( url
, req
.mime
, req
.notify
, req
.reload
);
837 QString
NSPluginInstance::normalizedURL(const QString
& url
) const {
839 // ### for dfaure: KUrl(KUrl("http://www.youtube.com/?v=JvOSnRD5aNk"), KUrl("javascript:window.location+"__flashplugin_unique__"));
841 //### hack, prolly evil, etc.
842 if (url
.startsWith("javascript:"))
847 KConfig
_cfg( "kcmnspluginrc" );
848 KConfigGroup
cfg(&_cfg
, "Misc");
850 if (!cfg
.readEntry("HTTP URLs Only", false) ||
851 inURL
.protocol() == "http" ||
852 inURL
.protocol() == "https" ||
853 inURL
.protocol() == "javascript") {
857 // Allow: javascript:, http, https, or no protocol (match loading)
858 kDebug(1431) << "NSPluginInstance::normalizedURL - I don't think so. http or https only!";
863 void NSPluginInstance::requestURL( const QString
&url
, const QString
&mime
,
864 const QString
&target
, void *notify
, bool forceNotify
, bool reload
)
866 // Generally this should already be done, but let's be safe for now.
867 QString nurl
= normalizedURL(url
);
872 kDebug(1431) << "NSPluginInstance::requestURL url=" << nurl
<< " target=" << target
<< " notify=" << notify
;
873 _waitingRequests
.enqueue( new Request( nurl
, mime
, target
, notify
, forceNotify
, reload
) );
874 _timer
->setSingleShot( true );
875 _timer
->start( 100 );
879 void NSPluginInstance::postURL( const QString
&url
, const QByteArray
& data
,
881 const QString
&target
, void *notify
,
882 const KParts::OpenUrlArguments
& args
,
883 const KParts::BrowserArguments
& browserArgs
,
886 // Generally this should already be done, but let's be safe for now.
887 QString nurl
= normalizedURL(url
);
892 kDebug(1431) << "NSPluginInstance::postURL url=" << nurl
<< " target=" << target
<< " notify=" << notify
;
893 _waitingRequests
.enqueue( new Request( nurl
, data
, mime
, target
, notify
, args
, browserArgs
, forceNotify
) );
894 _timer
->setSingleShot( true );
895 _timer
->start( 100 );
899 void NSPluginInstance::emitStatus(const QString
&message
)
902 _callback
->statusMessage( message
);
906 void NSPluginInstance::streamFinished( NSPluginStreamBase
* strm
)
908 kDebug(1431) << "-> NSPluginInstance::streamFinished";
909 emitStatus( QString() );
910 _streams
.removeOne(strm
);
912 _timer
->setSingleShot( true );
913 _timer
->start( 100 );
916 void NSPluginInstance::setupWindow(int winId
, int w
, int h
)
918 kDebug(1431) << "-> NSPluginInstance::setupWindow( winid =" << winId
<< " w=" << w
<< ", h=" << h
<< " ) ";
920 _pluginHost
->setupWindow(winId
, w
, h
);
922 kWarning(1431) << "No plugin host!";
924 kDebug(1431) << "<- NSPluginInstance::setupWindow";
930 void NSPluginInstance::resizePlugin(int clientWinId
, int w
, int h
)
932 kDebug() << _width
<< w
<< _height
<< h
<< _embedded
;
935 if (w
== _width
&& h
== _height
)
937 _pluginHost
->resizePlugin(clientWinId
, w
, h
);
943 void NSPluginInstance::javascriptResult(int id
, const QString
&result
) {
944 QMap
<int, Request
*>::iterator i
= _jsrequests
.find( id
);
945 if (i
!= _jsrequests
.end()) {
946 Request
*req
= i
.value();
947 _jsrequests
.erase( i
);
948 NSPluginStream
*s
= new NSPluginStream( this );
949 connect( s
, SIGNAL(finished(NSPluginStreamBase
*)),
950 SLOT(streamFinished(NSPluginStreamBase
*)) );
951 _streams
.append( s
);
953 int len
= result
.length();
954 s
->create( req
->url
, QString("text/plain"), req
->notify
, req
->forceNotify
);
955 kDebug(1431) << "javascriptResult has been called with: "<<result
;
957 QByteArray
data(len
+ 1, 0);
958 memcpy(data
.data(), result
.toLatin1(), len
);
962 len
= 7; // "unknown"
963 QByteArray
data(len
+ 1, 0);
964 memcpy(data
.data(), "unknown", len
);
975 NPError
NSPluginInstance::NPGetValue(NPPVariable variable
, void *value
)
978 kDebug() << "FIXME: value==0 in NSPluginInstance::NPGetValue";
979 return NPERR_GENERIC_ERROR
;
982 if (!_pluginFuncs
.getvalue
)
983 return NPERR_GENERIC_ERROR
;
985 NPError error
= _pluginFuncs
.getvalue(_npp
, variable
, value
);
987 CHECK(GetValue
,error
);
991 NPError
NSPluginInstance::NPSetValue(NPNVariable variable
, void *value
)
994 kDebug() << "FIXME: value==0 in NSPluginInstance::NPSetValue";
995 return NPERR_GENERIC_ERROR
;
998 if (!_pluginFuncs
.setvalue
)
999 return NPERR_GENERIC_ERROR
;
1001 NPError error
= _pluginFuncs
.setvalue(_npp
, variable
, value
);
1003 CHECK(SetValue
,error
);
1007 NPError
NSPluginInstance::NPSetWindow(NPWindow
*window
)
1010 kDebug() << "FIXME: window==0 in NSPluginInstance::NPSetWindow";
1011 return NPERR_GENERIC_ERROR
;
1014 if (!_pluginFuncs
.setwindow
)
1015 return NPERR_GENERIC_ERROR
;
1017 NPError error
= _pluginFuncs
.setwindow(_npp
, window
);
1019 CHECK(SetWindow
,error
);
1023 NPError
NSPluginInstance::NPDestroyStream(NPStream
*stream
, NPReason reason
)
1026 kDebug() << "FIXME: stream==0 in NSPluginInstance::NPDestroyStream";
1027 return NPERR_GENERIC_ERROR
;
1030 if (!_pluginFuncs
.destroystream
)
1031 return NPERR_GENERIC_ERROR
;
1033 NPError error
= _pluginFuncs
.destroystream(_npp
, stream
, reason
);
1035 CHECK(DestroyStream
,error
);
1039 NPError
NSPluginInstance::NPNewStream(NPMIMEType type
, NPStream
*stream
, NPBool seekable
, uint16
*stype
)
1042 kDebug() << "FIXME: stream==0 in NSPluginInstance::NPNewStream";
1043 return NPERR_GENERIC_ERROR
;
1047 kDebug() << "FIXME: stype==0 in NSPluginInstance::NPNewStream";
1048 return NPERR_GENERIC_ERROR
;
1051 if (!_pluginFuncs
.newstream
)
1052 return NPERR_GENERIC_ERROR
;
1054 NPError error
= _pluginFuncs
.newstream(_npp
, type
, stream
, seekable
, stype
);
1056 CHECK(NewStream
,error
);
1060 void NSPluginInstance::NPStreamAsFile(NPStream
*stream
, const char *fname
)
1063 kDebug() << "FIXME: stream==0 in NSPluginInstance::NPStreamAsFile";
1068 kDebug() << "FIXME: fname==0 in NSPluginInstance::NPStreamAsFile";
1072 if (!_pluginFuncs
.asfile
)
1075 _pluginFuncs
.asfile(_npp
, stream
, fname
);
1079 int32
NSPluginInstance::NPWrite(NPStream
*stream
, int32 offset
, int32 len
, void *buf
)
1082 kDebug() << "FIXME: stream==0 in NSPluginInstance::NPWrite";
1087 kDebug() << "FIXME: buf==0 in NSPluginInstance::NPWrite";
1091 if (!_pluginFuncs
.write
)
1094 return _pluginFuncs
.write(_npp
, stream
, offset
, len
, buf
);
1098 int32
NSPluginInstance::NPWriteReady(NPStream
*stream
)
1101 kDebug() << "FIXME: stream==0 in NSPluginInstance::NPWriteReady";
1105 if (!_pluginFuncs
.writeready
)
1108 return _pluginFuncs
.writeready(_npp
, stream
);
1112 void NSPluginInstance::NPURLNotify(const QString
&url
, NPReason reason
, void *notifyData
)
1114 if (!_pluginFuncs
.urlnotify
)
1117 _pluginFuncs
.urlnotify(_npp
, url
.toAscii(), reason
, notifyData
);
1121 void NSPluginInstance::addTempFile(KTemporaryFile
*tmpFile
)
1123 _tempFiles
.append(tmpFile
);
1126 static bool has_focus
= false;
1128 void NSPluginInstance::gotFocusIn()
1133 void NSPluginInstance::gotFocusOut()
1139 // Prevent plugins from polling the keyboard regardless of focus.
1140 static int (*real_xquerykeymap
)( Display
*, char[32] ) = NULL
;
1142 extern "C" KDE_EXPORT
1143 int XQueryKeymap( Display
* dpy
, char k
[32] )
1145 if( real_xquerykeymap
== NULL
)
1146 real_xquerykeymap
= (int (*)( Display
*, char[32] )) dlsym( RTLD_NEXT
, "XQueryKeymap" );
1148 return real_xquerykeymap( dpy
, k
);
1154 /***************************************************************************/
1156 NSPluginViewer::NSPluginViewer( QObject
*parent
)
1159 (void) new ViewerAdaptor( this );
1160 QDBusConnection::sessionBus().registerObject( "/Viewer", this );
1162 QObject::connect(QDBusConnection::sessionBus().interface(),
1163 SIGNAL(serviceOwnerChanged(const QString
&, const QString
&, const QString
&)),
1164 this, SLOT(appChanged( const QString
&, const QString
&, const QString
&)));
1168 NSPluginViewer::~NSPluginViewer()
1170 kDebug(1431) << "NSPluginViewer::~NSPluginViewer";
1174 void NSPluginViewer::appChanged( const QString
& id
, const QString
& oldOwner
, const QString
& newOwner
) {
1175 if ( oldOwner
.isEmpty() || !newOwner
.isEmpty() ) // only care about unregistering apps
1178 QMap
<QString
, NSPluginClass
*>::iterator it
= _classes
.begin();
1179 const QMap
<QString
, NSPluginClass
*>::iterator end
= _classes
.end();
1180 for ( ; it
!= end
; ++it
)
1182 if (it
.value()->app() == oldOwner
) {
1183 it
= _classes
.erase(it
);
1187 if (_classes
.isEmpty()) {
1193 void NSPluginViewer::shutdown()
1195 kDebug(1431) << "NSPluginViewer::shutdown";
1201 QDBusObjectPath
NSPluginViewer::newClass( const QString
& plugin
, const QString
& senderId
)
1203 kDebug(1431) << "NSPluginViewer::NewClass( " << plugin
<< ")";
1205 // search existing class
1206 NSPluginClass
*cls
= _classes
.value( plugin
);
1209 cls
= new NSPluginClass( plugin
, this );
1210 cls
->setApp(senderId
.toLatin1());
1211 if ( cls
->error() ) {
1212 kError(1431) << "Can't create plugin class" << endl
;
1214 return QDBusObjectPath();
1217 _classes
.insert( plugin
, cls
);
1220 return QDBusObjectPath(cls
->objectName());
1224 /****************************************************************************/
1226 static int s_classCounter
= 0;
1228 bool NSPluginClass::s_initedGTK
= false;
1230 typedef void gtkInitFunc(int *argc
, char ***argv
);
1232 NSPluginClass::NSPluginClass( const QString
&library
,
1236 (void) new ClassAdaptor( this );
1237 // The object name is used to store the dbus object path
1238 setObjectName( QString( "/Class_" ) + QString::number( ++s_classCounter
) );
1239 QDBusConnection::sessionBus().registerObject( objectName(), this );
1241 // initialize members
1242 _handle
= KLibLoader::self()->library(QFile::encodeName(library
));
1244 _constructed
= false;
1246 _NP_GetMIMEDescription
= 0;
1250 _timer
= new QTimer( this );
1251 connect( _timer
, SIGNAL(timeout()), SLOT(timer()) );
1255 kDebug(1431) << "Could not dlopen " << library
;
1259 // get exported lib functions
1260 _NP_GetMIMEDescription
= (NP_GetMIMEDescriptionUPP
*)_handle
->resolveFunction("NP_GetMIMEDescription");
1261 _NP_Initialize
= (NP_InitializeUPP
*)_handle
->resolveFunction("NP_Initialize");
1262 _NP_Shutdown
= (NP_ShutdownUPP
*)_handle
->resolveFunction("NP_Shutdown");
1264 // check for valid returned ptrs
1265 if (!_NP_GetMIMEDescription
) {
1266 kDebug(1431) << "Could not get symbol NP_GetMIMEDescription";
1270 if (!_NP_Initialize
) {
1271 kDebug(1431) << "Could not get symbol NP_Initialize";
1275 if (!_NP_Shutdown
) {
1276 kDebug(1431) << "Could not get symbol NP_Shutdown";
1280 // initialize plugin
1281 kDebug(1431) << "Plugin library " << library
<< " loaded!";
1283 // see if it uses gtk
1285 gtkInitFunc
* gtkInit
= (gtkInitFunc
*)_handle
->resolveFunction("gtk_init");
1287 kDebug(1431) << "Calling gtk_init for the plugin";
1288 // Prevent gtk_init() from replacing the X error handlers, since the Gtk
1289 // handlers abort when they receive an X error, thus killing the viewer.
1290 int (*old_error_handler
)(Display
*,XErrorEvent
*) = XSetErrorHandler(0);
1291 int (*old_io_error_handler
)(Display
*) = XSetIOErrorHandler(0);
1293 XSetErrorHandler(old_error_handler
);
1294 XSetIOErrorHandler(old_io_error_handler
);
1299 _constructed
= true;
1300 _error
= initialize()!=NPERR_NO_ERROR
;
1304 NSPluginClass::~NSPluginClass()
1306 qDeleteAll( _instances
);
1307 qDeleteAll( _trash
);
1315 void NSPluginClass::timer()
1318 while ( !_trash
.isEmpty() ) {
1319 NSPluginInstance
*it
= _trash
.takeFirst();
1320 int i
= _instances
.indexOf(it
);
1322 delete _instances
.takeAt(i
);
1323 else // there should be no instansces in trash, which are not in _instances
1329 int NSPluginClass::initialize()
1331 kDebug(1431) << "NSPluginClass::Initialize()";
1333 if ( !_constructed
)
1334 return NPERR_GENERIC_ERROR
;
1336 // initialize nescape exported functions
1337 memset(&_pluginFuncs
, 0, sizeof(_pluginFuncs
));
1338 memset(&_nsFuncs
, 0, sizeof(_nsFuncs
));
1340 _pluginFuncs
.size
= sizeof(_pluginFuncs
);
1341 _nsFuncs
.size
= sizeof(_nsFuncs
);
1342 _nsFuncs
.version
= (NP_VERSION_MAJOR
<< 8) + NP_VERSION_MINOR
;
1343 _nsFuncs
.geturl
= g_NPN_GetURL
;
1344 _nsFuncs
.posturl
= g_NPN_PostURL
;
1345 _nsFuncs
.requestread
= g_NPN_RequestRead
;
1346 _nsFuncs
.newstream
= g_NPN_NewStream
;
1347 _nsFuncs
.write
= g_NPN_Write
;
1348 _nsFuncs
.destroystream
= g_NPN_DestroyStream
;
1349 _nsFuncs
.status
= g_NPN_Status
;
1350 _nsFuncs
.uagent
= g_NPN_UserAgent
;
1351 _nsFuncs
.memalloc
= g_NPN_MemAlloc
;
1352 _nsFuncs
.memfree
= g_NPN_MemFree
;
1353 _nsFuncs
.memflush
= g_NPN_MemFlush
;
1354 _nsFuncs
.reloadplugins
= g_NPN_ReloadPlugins
;
1355 _nsFuncs
.getJavaEnv
= g_NPN_GetJavaEnv
;
1356 _nsFuncs
.getJavaPeer
= g_NPN_GetJavaPeer
;
1357 _nsFuncs
.geturlnotify
= g_NPN_GetURLNotify
;
1358 _nsFuncs
.posturlnotify
= g_NPN_PostURLNotify
;
1359 _nsFuncs
.getvalue
= g_NPN_GetValue
;
1360 _nsFuncs
.setvalue
= g_NPN_SetValue
;
1361 _nsFuncs
.invalidaterect
= g_NPN_InvalidateRect
;
1362 _nsFuncs
.invalidateregion
= g_NPN_InvalidateRegion
;
1363 _nsFuncs
.forceredraw
= g_NPN_ForceRedraw
;
1365 _nsFuncs
.pushpopupsenabledstate
= g_NPN_PushPopupsEnabledState
;
1366 _nsFuncs
.poppopupsenabledstate
= g_NPN_PopPopupsEnabledState
;
1368 // initialize plugin
1369 NPError error
= _NP_Initialize(&_nsFuncs
, &_pluginFuncs
);
1370 assert(_nsFuncs
.size
== sizeof(_nsFuncs
));
1371 CHECK(Initialize
,error
);
1375 QString
NSPluginClass::getMIMEDescription()
1377 return _NP_GetMIMEDescription();
1381 void NSPluginClass::shutdown()
1383 kDebug(1431) << "NSPluginClass::shutdown error=" << _error
;
1384 if( _NP_Shutdown
&& !_error
)
1389 QDBusObjectPath
NSPluginClass::newInstance( const QString
&url
, const QString
&mimeType
, bool embed
,
1390 const QStringList
&argn
, const QStringList
&argv
,
1391 const QString
&appId
, const QString
&callbackId
, bool reload
)
1393 kDebug(1431) << "-> NSPluginClass::NewInstance";
1395 if ( !_constructed
)
1396 return QDBusObjectPath();
1398 // copy parameters over
1399 unsigned int argc
= argn
.count();
1400 char **_argn
= new char*[argc
];
1401 char **_argv
= new char*[argc
];
1403 QString baseURL
= url
;
1405 for (unsigned int i
=0; i
<argc
; i
++)
1407 QByteArray encN
= argn
[i
].toUtf8();
1408 QByteArray encV
= argv
[i
].toUtf8();
1410 const char *n
= encN
;
1411 const char *v
= encV
;
1413 _argn
[i
] = strdup(n
);
1414 _argv
[i
] = strdup(v
);
1416 if (!strcasecmp(_argn
[i
], "__KHTML__PLUGINBASEURL")) baseURL
= _argv
[i
];
1417 kDebug(1431) << "argn=" << _argn
[i
] << " argv=" << _argv
[i
];
1420 // create plugin instance
1422 strncpy(mime
, mimeType
.toAscii(), 255);
1424 NPP npp
= (NPP
)malloc(sizeof(NPP_t
)); // I think we should be using
1425 // malloc here, just to be safe,
1426 // since the nsplugin plays with
1428 memset(npp
, 0, sizeof(NPP_t
));
1431 // create plugin instance
1432 NPError error
= _pluginFuncs
.newp(mime
, npp
, embed
? NP_EMBED
: NP_FULL
,
1433 argc
, _argn
, _argv
, 0);
1435 kDebug(1431) << "NPP_New = " << (int)error
;
1437 // free arrays with arguments
1442 if ( error
!=NPERR_NO_ERROR
)
1445 kDebug(1431) << "<- PluginClass::NewInstance = 0";
1446 return QDBusObjectPath();
1449 // Create plugin instance object
1450 NSPluginInstance
*inst
= new NSPluginInstance( npp
, &_pluginFuncs
, _handle
,
1451 baseURL
, mimeType
, appId
,
1452 callbackId
, embed
, this );
1454 // set the current plugin instance
1455 NSPluginInstance::setLastPluginInstance(inst
);
1457 // create source stream
1458 if ( !src
.isEmpty() )
1459 inst
->requestURL( src
, mimeType
, QString(), 0, false, reload
);
1461 _instances
.append( inst
);
1462 return QDBusObjectPath(inst
->objectName());
1466 void NSPluginClass::destroyInstance( NSPluginInstance
* inst
)
1468 // be sure we don't deal with a dangling pointer
1469 if ( NSPluginInstance::lastPluginInstance() == inst
)
1470 NSPluginInstance::setLastPluginInstance(0);
1472 // mark for destruction
1473 _trash
.append( inst
);
1474 timer(); //_timer->start( 0, TRUE );
1478 /****************************************************************************/
1480 NSPluginStreamBase::NSPluginStreamBase( NSPluginInstance
*instance
)
1481 : QObject( instance
), _instance(instance
), _stream(0), _tempFile(0L),
1482 _pos(0), _queuePos(0), _error(false)
1488 NSPluginStreamBase::~NSPluginStreamBase()
1491 _instance
->NPDestroyStream( _stream
, NPRES_USER_BREAK
);
1492 if (_stream
&& _stream
->url
)
1493 free(const_cast<char*>(_stream
->url
));
1503 void NSPluginStreamBase::stop()
1508 void NSPluginStreamBase::inform()
1517 // inform the plugin
1518 _instance
->NPNewStream( _mimeType
.isEmpty() ? (char *) "text/plain" : (char*)_mimeType
.data(),
1519 _stream
, false, &_streamType
);
1520 kDebug(1431) << "NewStream stype=" << _streamType
<< " url=" << _url
<< " mime=" << _mimeType
;
1522 // prepare data transfer
1525 if ( _streamType
==NP_ASFILE
|| _streamType
==NP_ASFILEONLY
) {
1526 _onlyAsFile
= _streamType
==NP_ASFILEONLY
;
1527 if ( KUrl(_url
).isLocalFile() ) {
1528 kDebug(1431) << "local file";
1529 // local file can be passed directly
1530 _fileURL
= KUrl(_url
).path();
1532 // without streaming stream is finished already
1533 if ( _onlyAsFile
) {
1534 kDebug() << "local file AS_FILE_ONLY";
1538 kDebug() << "remote file";
1540 // stream into temporary file (use lower() in case the
1541 // filename as an upper case X in it)
1542 _tempFile
= new KTemporaryFile
;
1544 _fileURL
= _tempFile
->fileName();
1545 kDebug() << "saving into " << _fileURL
;
1552 bool NSPluginStreamBase::create( const QString
& url
, const QString
& mimeType
, void *notify
, bool forceNotify
)
1558 _notifyData
= notify
;
1561 _onlyAsFile
= false;
1562 _streamType
= NP_NORMAL
;
1564 _forceNotify
= forceNotify
;
1566 // create new stream
1567 _stream
= new NPStream
;
1568 _stream
->ndata
= this;
1569 _stream
->url
= strdup(url
.toAscii());
1572 _stream
->lastmodified
= 0;
1573 _stream
->notifyData
= _notifyData
;
1575 _mimeType
= mimeType
;
1580 void NSPluginStreamBase::updateURL( const KUrl
& newURL
)
1583 free(const_cast<char*>(_stream
->url
));
1584 _stream
->url
= strdup(_url
.url().toLatin1().data());
1587 int NSPluginStreamBase::process( const QByteArray
&data
, int start
)
1589 int32 max
, sent
, to_sent
, len
;
1591 #warning added a const_cast
1593 char *d
= const_cast<char*>(data
.data()) + start
;
1595 to_sent
= data
.size() - start
;
1600 max
= _instance
->NPWriteReady(_stream
);
1601 //kDebug(1431) << "to_sent == " << to_sent << " and max = " << max;
1602 len
= qMin(max
, to_sent
);
1604 //kDebug(1431) << "-> Feeding stream to plugin: offset=" << _pos << ", len=" << len;
1605 sent
= _instance
->NPWrite( _stream
, _pos
, len
, d
);
1606 //kDebug(1431) << "<- Feeding stream: sent = " << sent;
1608 if (sent
== 0) // interrupt the stream for a few ms
1612 // stream data rejected/error
1613 kDebug(1431) << "stream data rejected/error";
1619 _tempFile
->write(d
, sent
);
1627 return data
.size() - to_sent
;
1631 bool NSPluginStreamBase::pump()
1633 //kDebug(1431) << "queue pos " << _queuePos << ", size " << _queue.size();
1637 if ( _queuePos
<_queue
.size() ) {
1640 // handle AS_FILE_ONLY streams
1641 if ( _onlyAsFile
) {
1643 _tempFile
->write( _queue
, _queue
.size() );
1645 newPos
= _queuePos
+_queue
.size();
1648 newPos
= process( _queue
, _queuePos
);
1652 if ( newPos
==_queuePos
)
1660 // return true if queue finished
1661 return _queuePos
>=_queue
.size();
1665 void NSPluginStreamBase::queue( const QByteArray
&data
)
1673 kDebug(1431) << "new queue size=" << data.size()
1674 << " data=" << (void*)data.data()
1675 << " queue=" << (void*)_queue.data() << " qsize="
1676 << _queue.size() << endl;
1681 void NSPluginStreamBase::finish( bool err
)
1683 kDebug(1431) << "finish error=" << err
;
1694 _instance
->addTempFile( _tempFile
);
1698 if ( !_fileURL
.isEmpty() ) {
1699 kDebug() << "stream as file " << _fileURL
;
1700 _instance
->NPStreamAsFile( _stream
, _fileURL
.toAscii() );
1703 _instance
->NPDestroyStream( _stream
, NPRES_DONE
);
1704 if (_notifyData
|| _forceNotify
)
1705 _instance
->NPURLNotify( _url
.url(), NPRES_DONE
, _notifyData
);
1713 _instance
->NPDestroyStream( _stream
, NPRES_NETWORK_ERR
);
1714 if (_notifyData
|| _forceNotify
)
1715 _instance
->NPURLNotify( _url
.url(), NPRES_NETWORK_ERR
, _notifyData
);
1719 if (_stream
&& _stream
->url
)
1720 free(const_cast<char *>(_stream
->url
));
1724 // destroy NSPluginStream object
1725 emit
finished( this );
1729 /****************************************************************************/
1731 NSPluginBufStream::NSPluginBufStream( class NSPluginInstance
*instance
)
1732 : NSPluginStreamBase( instance
)
1734 _timer
= new QTimer( this );
1735 connect( _timer
, SIGNAL(timeout()), this, SLOT(timer()) );
1739 NSPluginBufStream::~NSPluginBufStream()
1745 bool NSPluginBufStream::get( const QString
& url
, const QString
& mimeType
,
1746 const QByteArray
&buf
, void *notifyData
,
1749 _singleShot
= singleShot
;
1750 if ( create( url
, mimeType
, notifyData
) ) {
1752 _timer
->setSingleShot( true );
1753 _timer
->start( 100 );
1760 void NSPluginBufStream::timer()
1762 bool finished
= pump();
1767 if ( !finished
&& tries()<=8 ) {
1768 _timer
->setSingleShot( true );
1769 _timer
->start( 100 );
1771 finish( error() || tries()>8 );
1777 /****************************************************************************/
1779 NSPluginStream::NSPluginStream( NSPluginInstance
*instance
)
1780 : NSPluginStreamBase( instance
), _job(0)
1782 _resumeTimer
= new QTimer( this );
1783 connect(_resumeTimer
, SIGNAL(timeout()), this, SLOT(resume()));
1787 NSPluginStream::~NSPluginStream()
1790 _job
->kill( KJob::Quietly
);
1794 bool NSPluginStream::get( const QString
& url
, const QString
& mimeType
,
1795 void *notify
, bool reload
)
1797 // create new stream
1798 if ( create( url
, mimeType
, notify
) ) {
1799 // start the kio job
1800 _job
= KIO::get(KUrl( url
), KIO::NoReload
, KIO::HideProgressInfo
);
1801 _job
->addMetaData("errorPage", "false");
1802 _job
->addMetaData("AllowCompressedPage", "false");
1804 _job
->addMetaData("cache", "reload");
1806 connect(_job
, SIGNAL(data(KIO::Job
*, const QByteArray
&)),
1807 SLOT(data(KIO::Job
*, const QByteArray
&)));
1808 connect(_job
, SIGNAL(result(KJob
*)), SLOT(result(KJob
*)));
1809 connect(_job
, SIGNAL(totalSize(KJob
*, qulonglong
)),
1810 SLOT(totalSize(KJob
*, qulonglong
)));
1811 connect(_job
, SIGNAL(mimetype(KIO::Job
*, const QString
&)),
1812 SLOT(mimetype(KIO::Job
*, const QString
&)));
1813 connect(_job
, SIGNAL(redirection(KIO::Job
*, const KUrl
&)),
1814 SLOT(redirection(KIO::Job
*, const KUrl
&)));
1821 bool NSPluginStream::post( const QString
& url
, const QByteArray
& data
,
1822 const QString
& mimeType
, void *notify
, const KParts::OpenUrlArguments
& args
,
1823 const KParts::BrowserArguments
& browserArgs
)
1826 // create new stream
1827 if ( create( url
, mimeType
, notify
) ) {
1828 // start the kio job
1829 _job
= KIO::http_post(KUrl( url
), data
, KIO::HideProgressInfo
);
1830 _job
->addMetaData("content-type", browserArgs
.contentType());
1831 _job
->addMetaData("errorPage", "false");
1832 _job
->addMetaData("AllowCompressedPage", "false");
1833 connect(_job
, SIGNAL(data(KIO::Job
*, const QByteArray
&)),
1834 SLOT(data(KIO::Job
*, const QByteArray
&)));
1835 connect(_job
, SIGNAL(result(KJob
*)), SLOT(result(KJob
*)));
1836 connect(_job
, SIGNAL(totalSize(KJob
*, qulonglong
)),
1837 SLOT(totalSize(KJob
*, qulonglong
)));
1838 connect(_job
, SIGNAL(mimetype(KIO::Job
*, const QString
&)),
1839 SLOT(mimetype(KIO::Job
*, const QString
&)));
1840 connect(_job
, SIGNAL(redirection(KIO::Job
*, const KUrl
&)),
1841 SLOT(redirection(KIO::Job
*, const KUrl
&)));
1848 void NSPluginStream::data(KIO::Job
*, const QByteArray
&data
)
1850 //kDebug(1431) << "NSPluginStream::data - job=" << (void*)job << " data size=" << data.size();
1854 _resumeTimer
->setSingleShot( true );
1855 _resumeTimer
->start( 100 );
1859 void NSPluginStream::redirection(KIO::Job
* /*job*/, const KUrl
& url
)
1864 void NSPluginStream::totalSize(KJob
* job
, qulonglong size
)
1866 kDebug(1431) << "NSPluginStream::totalSize - job=" << (void*)job
<< " size=" << KIO::number(size
);
1867 _stream
->end
= size
;
1870 void NSPluginStream::mimetype(KIO::Job
* job
, const QString
&mimeType
)
1872 kDebug(1431) << "NSPluginStream::QByteArray - job=" << (void*)job
<< " mimeType=" << mimeType
;
1873 _mimeType
= mimeType
;
1879 void NSPluginStream::resume()
1881 if ( error() || tries()>8 ) {
1882 _job
->kill( KJob::Quietly
);
1888 kDebug(1431) << "resume job";
1891 kDebug(1431) << "restart timer";
1892 _resumeTimer
->setSingleShot( true );
1893 _resumeTimer
->start( 100 );
1898 void NSPluginStream::result(KJob
*job
)
1900 int err
= job
->error();
1902 finish( err
!=0 || error() );
1905 #include "nsplugin.moc"
1906 // vim: ts=4 sw=4 et