mirror of
https://invent.kde.org/system/dolphin
synced 2024-11-05 18:47:12 +00:00
2019 lines
57 KiB
C++
2019 lines
57 KiB
C++
/*
|
|
This is an encapsulation of the Netscape plugin API.
|
|
|
|
Copyright (c) 2000 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
|
|
Stefan Schimanski <1Stein@gmx.de>
|
|
2003-2005 George Staikos <staikos@kde.org>
|
|
2007, 2008, 2010 Maksim Orlovich <maksim@kde.org>
|
|
2006, 2007, 2008 Apple Inc.
|
|
2008 Collabora, Ltd.
|
|
2008 Sebastian Sauer <mail@dipe.org>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "nsplugin.h"
|
|
#include "pluginhost_xembed.h"
|
|
#include "pluginhost_xt.h"
|
|
#include "resolve.h"
|
|
#include "classadaptor.h"
|
|
#include "instanceadaptor.h"
|
|
#include "vieweradaptor.h"
|
|
#include "scripting.h"
|
|
|
|
#include "nsplugins_callback_interface.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QTimer>
|
|
#include <QApplication>
|
|
|
|
#ifdef Bool
|
|
#undef Bool
|
|
#endif
|
|
|
|
#include <kconfig.h>
|
|
#include <kconfiggroup.h>
|
|
#include <kdebug.h>
|
|
#include <kglobal.h>
|
|
#include <kio/netaccess.h>
|
|
#include <kprotocolmanager.h>
|
|
#include <klibrary.h>
|
|
#include <klocale.h>
|
|
#include <kstandarddirs.h>
|
|
#include <ktemporaryfile.h>
|
|
#include <kurl.h>
|
|
#include <QX11Info>
|
|
#include <QProcess>
|
|
|
|
#include <X11/Intrinsic.h>
|
|
#include <X11/Composite.h>
|
|
#include <X11/Constraint.h>
|
|
#include <X11/Shell.h>
|
|
#include <X11/StringDefs.h>
|
|
|
|
// provide these symbols when compiling with gcc 3.x
|
|
|
|
#if defined __GNUC__ && defined __GNUC_MINOR__
|
|
# define KDE_GNUC_PREREQ(maj, min) \
|
|
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
|
|
#else
|
|
# define KDE_GNUC_PREREQ(maj, min) 0
|
|
#endif
|
|
|
|
|
|
#if defined(__GNUC__) && KDE_GNUC_PREREQ(3,0)
|
|
extern "C" void* __builtin_new(size_t s)
|
|
{
|
|
return operator new(s);
|
|
}
|
|
|
|
extern "C" void __builtin_delete(void* p)
|
|
{
|
|
operator delete(p);
|
|
}
|
|
|
|
extern "C" void* __builtin_vec_new(size_t s)
|
|
{
|
|
return operator new[](s);
|
|
}
|
|
|
|
extern "C" void __builtin_vec_delete(void* p)
|
|
{
|
|
operator delete[](p);
|
|
}
|
|
|
|
extern "C" void __pure_virtual()
|
|
{
|
|
abort();
|
|
}
|
|
#endif
|
|
|
|
// The NSPluginInstance is always the ndata of the instance. Sometimes, plug-ins will call an instance-specific function
|
|
// with a NULL instance. To workaround this, we remember the last NSPluginInstance produced with the
|
|
// NSPluginClass::newInstance() method. This specifically works around Flash and Shockwave which do e.g. call NPN_Useragent
|
|
// with a NULL instance When we call NPP_New.
|
|
// At the moment we do setLastPluginInstance() only if the NSPluginInstance is created. Probably it would be more logical
|
|
// to do that more often to prevent some wired situations where we may end with the wrong NSPluginInstance for a plugin.
|
|
NSPluginInstance* NSPluginInstance::s_lastPluginInstance = 0;
|
|
NSPluginInstance* NSPluginInstance::lastPluginInstance() { return s_lastPluginInstance; }
|
|
void NSPluginInstance::setLastPluginInstance(NSPluginInstance* inst) { s_lastPluginInstance = inst; }
|
|
static NSPluginInstance* pluginViewForInstance(NPP instance)
|
|
{
|
|
if (instance && instance->ndata)
|
|
return static_cast<NSPluginInstance*>(instance->ndata);
|
|
return NSPluginInstance::lastPluginInstance();
|
|
}
|
|
|
|
// server side functions -----------------------------------------------------
|
|
|
|
// allocate memory
|
|
|
|
namespace kdeNsPluginViewer {
|
|
void *g_NPN_MemAlloc(uint32_t size)
|
|
{
|
|
void *mem = ::malloc(size);
|
|
|
|
//kDebug(1431) << "g_NPN_MemAlloc(), size=" << size << " allocated at " << mem;
|
|
|
|
return mem;
|
|
}
|
|
|
|
|
|
// free memory
|
|
void g_NPN_MemFree(void *ptr)
|
|
{
|
|
//kDebug(1431) << "g_NPN_MemFree() at " << ptr;
|
|
if (ptr)
|
|
::free(ptr);
|
|
}
|
|
|
|
}
|
|
|
|
uint32_t g_NPN_MemFlush(uint32_t size)
|
|
{
|
|
Q_UNUSED(size);
|
|
//kDebug(1431) << "g_NPN_MemFlush()";
|
|
// MAC OS only.. we don't use this
|
|
return 0;
|
|
}
|
|
|
|
|
|
// redraw
|
|
void g_NPN_ForceRedraw(NPP /*instance*/)
|
|
{
|
|
// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api3.html#999401
|
|
// FIXME
|
|
kDebug(1431) << "g_NPN_ForceRedraw() [unimplemented]";
|
|
}
|
|
|
|
|
|
// invalidate rect
|
|
void g_NPN_InvalidateRect(NPP /*instance*/, NPRect* /*invalidRect*/)
|
|
{
|
|
// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api7.html#999503
|
|
// FIXME
|
|
kDebug(1431) << "g_NPN_InvalidateRect() [unimplemented]";
|
|
}
|
|
|
|
|
|
// invalidate region
|
|
void g_NPN_InvalidateRegion(NPP /*instance*/, NPRegion /*invalidRegion*/)
|
|
{
|
|
// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api8.html#999528
|
|
// FIXME
|
|
kDebug(1431) << "g_NPN_InvalidateRegion() [unimplemented]";
|
|
}
|
|
|
|
|
|
// get value
|
|
NPError g_NPN_GetValue(NPP instance, NPNVariable variable, void *value)
|
|
{
|
|
kDebug(1431) << "g_NPN_GetValue(), variable=" << static_cast<int>(variable);
|
|
NSPluginInstance* inst = pluginViewForInstance(instance);
|
|
|
|
switch (variable)
|
|
{
|
|
case NPNVxDisplay:
|
|
*(void**)value = QX11Info::display();
|
|
return NPERR_NO_ERROR;
|
|
case NPNVxtAppContext:
|
|
*(void**)value = XtDisplayToApplicationContext(QX11Info::display());
|
|
return NPERR_NO_ERROR;
|
|
case NPNVjavascriptEnabledBool:
|
|
*(bool*)value = true;
|
|
return NPERR_NO_ERROR;
|
|
case NPNVasdEnabledBool:
|
|
// SmartUpdate - we don't do this
|
|
*(bool*)value = false;
|
|
return NPERR_NO_ERROR;
|
|
case NPNVisOfflineBool:
|
|
// Offline browsing - no thanks
|
|
*(bool*)value = false;
|
|
return NPERR_NO_ERROR;
|
|
case NPNVSupportsXEmbedBool:
|
|
// ### may depend on event loop setting
|
|
*(bool*)value = true;
|
|
return NPERR_NO_ERROR;
|
|
case NPNVToolkit:
|
|
// This is messy. OSS things want to see "Gtk2" here;
|
|
// but commercial flash works better if we return something else.
|
|
// So we return a KHTML classic, since we can work with
|
|
// the community members far easier.
|
|
*(NPNToolkitType*)value = (NPNToolkitType)0xFEEDABEE;
|
|
return NPERR_NO_ERROR;
|
|
case NPNVWindowNPObject:
|
|
if (inst && inst->scripting()) {
|
|
*(NPObject**)value = inst->scripting()->acquireWindow();
|
|
return NPERR_NO_ERROR;
|
|
} else {
|
|
kDebug(1431) << "script object queried, but no scripting active";
|
|
return NPERR_INVALID_PARAM;
|
|
}
|
|
#if 0
|
|
case NPNVPluginElementNPObject:
|
|
if (inst && inst->scripting()) {
|
|
*(NPObject**)value = inst->scripting()->acquirePluginElement();
|
|
return NPERR_NO_ERROR;
|
|
} else {
|
|
kDebug(1431) << "script object queried, but no scripting active";
|
|
return NPERR_INVALID_PARAM;
|
|
}
|
|
#endif
|
|
default:
|
|
kDebug(1431) << "g_NPN_GetValue(), [unimplemented] variable=" << variable;
|
|
return NPERR_INVALID_PARAM;
|
|
}
|
|
}
|
|
|
|
|
|
NPError g_NPN_DestroyStream(NPP instance, NPStream* stream,
|
|
NPReason reason)
|
|
{
|
|
// FIXME: is this correct? I imagine it is not. (GS)
|
|
kDebug(1431) << "g_NPN_DestroyStream()";
|
|
|
|
NSPluginInstance *inst = pluginViewForInstance(instance);
|
|
inst->streamFinished( (NSPluginStream *)stream->ndata );
|
|
|
|
switch (reason) {
|
|
case NPRES_DONE:
|
|
return NPERR_NO_ERROR;
|
|
case NPRES_USER_BREAK:
|
|
// FIXME: notify the user
|
|
case NPRES_NETWORK_ERR:
|
|
// FIXME: notify the user
|
|
default:
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
NPError g_NPN_RequestRead(NPStream* /*stream*/, NPByteRange* /*rangeList*/)
|
|
{
|
|
// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api16.html#999734
|
|
kDebug(1431) << "g_NPN_RequestRead() [unimplemented]";
|
|
|
|
// FIXME
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
NPError g_NPN_NewStream(NPP /*instance*/, NPMIMEType /*type*/,
|
|
const char* /*target*/, NPStream** /*stream*/)
|
|
{
|
|
// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api12.html#999628
|
|
kDebug(1431) << "g_NPN_NewStream() [unimplemented]";
|
|
|
|
// FIXME
|
|
// This creates a stream from the plugin to the browser of type "type" to
|
|
// display in "target"
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
int32_t g_NPN_Write(NPP /*instance*/, NPStream* /*stream*/, int32_t /*len*/, void* /*buf*/)
|
|
{
|
|
// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api21.html#999859
|
|
kDebug(1431) << "g_NPN_Write() [unimplemented]";
|
|
|
|
// FIXME
|
|
return 0;
|
|
}
|
|
|
|
|
|
// URL functions
|
|
NPError g_NPN_GetURL(NPP instance, const char *url, const char *target)
|
|
{
|
|
kDebug(1431) << "g_NPN_GetURL: url=" << url << " target=" << target;
|
|
|
|
NSPluginInstance *inst = pluginViewForInstance(instance);
|
|
if (inst) {
|
|
inst->requestURL( QString::fromLatin1(url), QString(),
|
|
QString::fromLatin1(target), 0 );
|
|
}
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
NPError g_NPN_GetURLNotify(NPP instance, const char *url, const char *target,
|
|
void* notifyData)
|
|
{
|
|
kDebug(1431) << "g_NPN_GetURLNotify: url=" << url << " target=" << target << " inst=" << (void*)instance;
|
|
NSPluginInstance *inst = pluginViewForInstance(instance);
|
|
if (inst) {
|
|
kDebug(1431) << "g_NPN_GetURLNotify: ndata=" << (void*)inst;
|
|
inst->requestURL( QString::fromLatin1(url), QString(),
|
|
QString::fromLatin1(target), notifyData, true );
|
|
}
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
NPError g_NPN_PostURLNotify(NPP instance, const char* url, const char* target,
|
|
uint32_t len, const char* buf, NPBool file, void* notifyData)
|
|
{
|
|
// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api14.html
|
|
kDebug(1431) << "g_NPN_PostURLNotify() [incomplete]";
|
|
kDebug(1431) << "url=[" << url << "] target=[" << target << "]";
|
|
QByteArray postdata;
|
|
KParts::OpenUrlArguments args;
|
|
KParts::BrowserArguments browserArgs;
|
|
|
|
if (len == 0) {
|
|
return NPERR_NO_DATA;
|
|
}
|
|
|
|
if (file) { // buf is a filename
|
|
QFile f(buf);
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
|
return NPERR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
// FIXME: this will not work because we need to strip the header out!
|
|
postdata = f.readAll();
|
|
f.close();
|
|
} else { // buf is raw data
|
|
// First strip out the header
|
|
const char *previousStart = buf;
|
|
uint32_t l;
|
|
bool previousCR = true;
|
|
|
|
for (l = 1;; ++l) {
|
|
if (l == len) {
|
|
break;
|
|
}
|
|
|
|
if (buf[l-1] == '\n' || (previousCR && buf[l-1] == '\r')) {
|
|
if (previousCR) { // header is done!
|
|
if ((buf[l-1] == '\r' && buf[l] == '\n') ||
|
|
(buf[l-1] == '\n' && buf[l] == '\r'))
|
|
l++;
|
|
l++;
|
|
previousStart = &buf[l-1];
|
|
break;
|
|
}
|
|
|
|
QString thisLine = QString::fromLatin1(previousStart, &buf[l-1] - previousStart).trimmed();
|
|
|
|
previousStart = &buf[l];
|
|
previousCR = true;
|
|
|
|
kDebug(1431) << "Found header line: [" << thisLine << "]";
|
|
if (thisLine.startsWith("Content-Type: ")) {
|
|
browserArgs.setContentType(thisLine);
|
|
}
|
|
} else {
|
|
previousCR = false;
|
|
}
|
|
}
|
|
|
|
postdata = QByteArray(previousStart, len - l + 1);
|
|
}
|
|
|
|
kDebug(1431) << "Post data: " << postdata.size() << " bytes";
|
|
#if 0
|
|
QFile f("/tmp/nspostdata");
|
|
f.open(QIODevice::WriteOnly);
|
|
f.write(postdata);
|
|
f.close();
|
|
#endif
|
|
|
|
if (!target || !*target) {
|
|
// Send the results of the post to the plugin
|
|
// (works by default)
|
|
} else if (!strcmp(target, "_current") || !strcmp(target, "_self") ||
|
|
!strcmp(target, "_top")) {
|
|
// Unload the plugin, put the results in the frame/window that the
|
|
// plugin was loaded in
|
|
// FIXME
|
|
} else if (!strcmp(target, "_new") || !strcmp(target, "_blank")){
|
|
// Open a new browser window and write the results there
|
|
// FIXME
|
|
} else {
|
|
// Write the results to the specified frame
|
|
// FIXME
|
|
}
|
|
|
|
NSPluginInstance *inst = pluginViewForInstance(instance);
|
|
if (inst && !inst->normalizedURL(QString::fromLatin1(url)).isNull()) {
|
|
inst->postURL( QString::fromLatin1(url), postdata, browserArgs.contentType(),
|
|
QString::fromLatin1(target), notifyData, args, browserArgs, true );
|
|
} else {
|
|
// Unsupported / insecure
|
|
return NPERR_INVALID_URL;
|
|
}
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
NPError g_NPN_PostURL(NPP instance, const char* url, const char* target,
|
|
uint32_t len, const char* buf, NPBool file)
|
|
{
|
|
// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api13.html
|
|
kDebug(1431) << "g_NPN_PostURL()";
|
|
kDebug(1431) << "url=[" << url << "] target=[" << target << "]";
|
|
QByteArray postdata;
|
|
KParts::OpenUrlArguments args;
|
|
KParts::BrowserArguments browserArgs;
|
|
|
|
if (len == 0) {
|
|
return NPERR_NO_DATA;
|
|
}
|
|
|
|
if (file) { // buf is a filename
|
|
QFile f(buf);
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
|
return NPERR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
// FIXME: this will not work because we need to strip the header out!
|
|
postdata = f.readAll();
|
|
f.close();
|
|
} else { // buf is raw data
|
|
// First strip out the header
|
|
const char *previousStart = buf;
|
|
uint32_t l;
|
|
bool previousCR = true;
|
|
|
|
for (l = 1;; ++l) {
|
|
if (l == len) {
|
|
break;
|
|
}
|
|
|
|
if (buf[l-1] == '\n' || (previousCR && buf[l-1] == '\r')) {
|
|
if (previousCR) { // header is done!
|
|
if ((buf[l-1] == '\r' && buf[l] == '\n') ||
|
|
(buf[l-1] == '\n' && buf[l] == '\r'))
|
|
l++;
|
|
l++;
|
|
previousStart = &buf[l-1];
|
|
break;
|
|
}
|
|
|
|
QString thisLine = QString::fromLatin1(previousStart, &buf[l-1] - previousStart).trimmed();
|
|
|
|
previousStart = &buf[l];
|
|
previousCR = true;
|
|
|
|
kDebug(1431) << "Found header line: [" << thisLine << "]";
|
|
if (thisLine.startsWith("Content-Type: ")) {
|
|
browserArgs.setContentType(thisLine);
|
|
}
|
|
} else {
|
|
previousCR = false;
|
|
}
|
|
}
|
|
|
|
postdata = QByteArray(previousStart, len - l + 1);
|
|
}
|
|
|
|
kDebug(1431) << "Post data: " << postdata.size() << " bytes";
|
|
#if 0
|
|
QFile f("/tmp/nspostdata");
|
|
f.open(QIODevice::WriteOnly);
|
|
f.write(postdata);
|
|
f.close();
|
|
#endif
|
|
|
|
if (!target || !*target) {
|
|
// Send the results of the post to the plugin
|
|
// (works by default)
|
|
} else if (!strcmp(target, "_current") || !strcmp(target, "_self") ||
|
|
!strcmp(target, "_top")) {
|
|
// Unload the plugin, put the results in the frame/window that the
|
|
// plugin was loaded in
|
|
// FIXME
|
|
} else if (!strcmp(target, "_new") || !strcmp(target, "_blank")){
|
|
// Open a new browser window and write the results there
|
|
// FIXME
|
|
} else {
|
|
// Write the results to the specified frame
|
|
// FIXME
|
|
}
|
|
|
|
NSPluginInstance *inst = pluginViewForInstance(instance);
|
|
if (inst && !inst->normalizedURL(QString::fromLatin1(url)).isNull()) {
|
|
inst->postURL( QString::fromLatin1(url), postdata, browserArgs.contentType(),
|
|
QString::fromLatin1(target), 0L, args, browserArgs, false );
|
|
} else {
|
|
// Unsupported / insecure
|
|
return NPERR_INVALID_URL;
|
|
}
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
// display status message
|
|
void g_NPN_Status(NPP instance, const char *message)
|
|
{
|
|
kDebug(1431) << "g_NPN_Status(): " << message;
|
|
|
|
if (!instance)
|
|
return;
|
|
|
|
// turn into an instance signal
|
|
NSPluginInstance *inst = pluginViewForInstance(instance);
|
|
|
|
inst->emitStatus(message);
|
|
}
|
|
|
|
|
|
static QByteArray uaStore;
|
|
static QByteArray uaEmpty("Gecko");
|
|
|
|
// inquire user agent
|
|
const char *g_NPN_UserAgent(NPP instance)
|
|
{
|
|
if (!instance)
|
|
return uaEmpty.data();
|
|
|
|
if (uaStore.isEmpty()) {
|
|
KProtocolManager kpm;
|
|
QString agent = kpm.userAgentForHost("nspluginviewer");
|
|
uaStore = agent.toLatin1();
|
|
}
|
|
|
|
kDebug(1431) << "g_NPN_UserAgent() = " << uaStore;
|
|
return uaStore.data();
|
|
}
|
|
|
|
// inquire version information
|
|
void g_NPN_Version(int *plugin_major, int *plugin_minor, int *browser_major, int *browser_minor)
|
|
{
|
|
kDebug(1431) << "g_NPN_Version()";
|
|
|
|
// FIXME: Use the sensible values
|
|
*browser_major = NP_VERSION_MAJOR;
|
|
*browser_minor = NP_VERSION_MINOR;
|
|
|
|
*plugin_major = NP_VERSION_MAJOR;
|
|
*plugin_minor = NP_VERSION_MINOR;
|
|
}
|
|
|
|
|
|
void g_NPN_ReloadPlugins(NPBool reloadPages)
|
|
{
|
|
// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api15.html#999713
|
|
kDebug(1431) << "g_NPN_ReloadPlugins()";
|
|
QString prog = KGlobal::dirs()->findExe("nspluginscan");
|
|
|
|
if (reloadPages) {
|
|
// This is the proper way, but it cannot be done because we have no
|
|
// handle to the caller! How stupid! We cannot force all konqi windows
|
|
// to reload - that would be evil.
|
|
//p.start(K3Process::Block);
|
|
// Let's only allow the caller to be reloaded, not everything.
|
|
//if (_callback)
|
|
// _callback->reloadPage();
|
|
QProcess::startDetached(prog);
|
|
} else {
|
|
QProcess::startDetached(prog);
|
|
}
|
|
}
|
|
|
|
|
|
// JAVA functions
|
|
void *g_NPN_GetJavaEnv()
|
|
{
|
|
kDebug(1431) << "g_NPN_GetJavaEnv() [unimplemented]";
|
|
// FIXME - what do these do? I can't find docs, and even Mozilla doesn't
|
|
// implement them
|
|
return 0;
|
|
}
|
|
|
|
|
|
void* g_NPN_GetJavaPeer(NPP /*instance*/)
|
|
{
|
|
kDebug(1431) << "g_NPN_GetJavaPeer() [unimplemented]";
|
|
// FIXME - what do these do? I can't find docs, and even Mozilla doesn't
|
|
// implement them
|
|
return 0;
|
|
}
|
|
|
|
|
|
NPError g_NPN_SetValue(NPP /*instance*/, NPPVariable variable, void* /*value*/)
|
|
{
|
|
kDebug(1431) << "g_NPN_SetValue() [unimplemented]";
|
|
switch (variable) {
|
|
case NPPVpluginWindowBool:
|
|
// FIXME
|
|
// If true, the plugin is windowless. If false, it is in a window.
|
|
case NPPVpluginTransparentBool:
|
|
// FIXME
|
|
// If true, the plugin is displayed transparent
|
|
default:
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
These two are in the ABI version 16 which we don't claim to support, but
|
|
flash uses anyway.
|
|
*/
|
|
static void g_NPN_PushPopupsEnabledState(NPP /*instance*/, NPBool enabled)
|
|
{
|
|
kDebug(1431) << "[unimplemented]" << enabled;
|
|
}
|
|
|
|
static void g_NPN_PopPopupsEnabledState(NPP /*instance*/)
|
|
{
|
|
kDebug(1431) << "[unimplemented]";
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
static int s_instanceCounter = 0;
|
|
|
|
NSPluginInstance::NSPluginInstance(NPPluginFuncs *pluginFuncs,
|
|
KLibrary *handle,
|
|
const QString &url, const QString &mimeType,
|
|
const QStringList &argn, const QStringList &argv,
|
|
const QString &appId, const QString &callbackId,
|
|
bool embed,
|
|
QObject *parent )
|
|
: QObject( parent )
|
|
{
|
|
// Setup d-bus infrastructure early, will need it for script stuff
|
|
kdeNsPluginViewer::initDBusTypes();
|
|
|
|
// The object name is the dbus object path
|
|
(void) new InstanceAdaptor( this );
|
|
setObjectName( QLatin1String( "/Instance_" ) + QString::number( ++s_instanceCounter ) );
|
|
QDBusConnection::sessionBus().registerObject( objectName(), this );
|
|
_callback = new org::kde::nsplugins::CallBack( appId, callbackId, QDBusConnection::sessionBus() );
|
|
|
|
|
|
_embedded = false;
|
|
_destroyed = false;
|
|
_handle = handle;
|
|
_numJSRequests = 0;
|
|
_scripting = 0;
|
|
|
|
// set the current plugin instance
|
|
NSPluginInstance::setLastPluginInstance(this);
|
|
|
|
memcpy(&_pluginFuncs, pluginFuncs, sizeof(_pluginFuncs));
|
|
|
|
// See want the scripting stuff very early, since newp can use it.
|
|
_scripting = new ScriptExportEngine(this);
|
|
|
|
// copy parameters over, and extract out base url if specified
|
|
int argc = argn.count();
|
|
char **_argn = new char*[argc];
|
|
char **_argv = new char*[argc];
|
|
|
|
QString baseURL = url;
|
|
for (int i=0; i<argc; i++)
|
|
{
|
|
QByteArray encN = argn[i].toUtf8();
|
|
QByteArray encV = argv[i].toUtf8();
|
|
|
|
_argn[i] = strdup(encN.constData());
|
|
_argv[i] = strdup(encV.constData());
|
|
|
|
if (argn[i] == QLatin1String("__KHTML__PLUGINBASEURL"))
|
|
baseURL = argv[i];
|
|
if (argn[i] == QLatin1String("__KHTML__PLUGINPAGEURL"))
|
|
_pageURL = argv[i];
|
|
kDebug(1431) << "argn=" << _argn[i] << " argv=" << _argv[i];
|
|
}
|
|
|
|
// create plugin instance
|
|
char* mime = strdup(mimeType.toAscii().constData());
|
|
_npp = (NPP)malloc(sizeof(NPP_t)); // I think we should be using
|
|
// malloc here, just to be safe,
|
|
// since the nsplugin plays with
|
|
// this thing
|
|
memset(_npp, 0, sizeof(NPP_t));
|
|
_npp->ndata = this;
|
|
|
|
// create actual plugin's instance
|
|
NPError error = _pluginFuncs.newp(mime, _npp, embed ? NP_EMBED : NP_FULL,
|
|
argc, _argn, _argv, 0);
|
|
|
|
kDebug(1431) << "NPP_New = " << (int)error;
|
|
|
|
// free arrays with arguments
|
|
delete [] _argn;
|
|
delete [] _argv;
|
|
|
|
// check for error
|
|
if ( error!=NPERR_NO_ERROR )
|
|
{
|
|
::free(_npp);
|
|
::free(mime);
|
|
kDebug(1431) << "<- newp failed";
|
|
_initializedOK = false;
|
|
return;
|
|
}
|
|
|
|
_initializedOK = true;
|
|
|
|
KUrl base(baseURL);
|
|
base.setFileName( QString() );
|
|
_baseURL = base.url();
|
|
|
|
_timer = new QTimer( this );
|
|
connect( _timer, SIGNAL(timeout()), SLOT(timer()) );
|
|
|
|
kDebug(1431) << "NSPluginInstance::NSPluginInstance";
|
|
kDebug(1431) << "pdata = " << _npp->pdata;
|
|
kDebug(1431) << "ndata = " << _npp->ndata;
|
|
|
|
// now let's see if the plugin offers any scriptable stuff, too.
|
|
_scripting->connectToPlugin();
|
|
|
|
// Create the appropriate host for the plugin type.
|
|
_pluginHost = 0;
|
|
int result = 0; /* false */
|
|
//### iceweasel does something odd here --- it enabled XEmbed for swfdec,
|
|
// even though that doesn't provide GetValue at all(!)
|
|
if (NPGetValue(NPPVpluginNeedsXEmbed, &result) == NPERR_NO_ERROR && result) {
|
|
kDebug(1431) << "plugin reqests XEmbed";
|
|
_pluginHost = new PluginHostXEmbed(this);
|
|
} else {
|
|
kDebug(1431) << "plugin requests Xt";
|
|
_pluginHost = new PluginHostXt(this);
|
|
}
|
|
|
|
XSync(QX11Info::display(), false);
|
|
}
|
|
|
|
NSPluginInstance::~NSPluginInstance()
|
|
{
|
|
kDebug(1431) << "-> ~NSPluginInstance";
|
|
destroy();
|
|
kDebug(1431) << "<- ~NSPluginInstance";
|
|
}
|
|
|
|
// Note: here we again narrow the types to the same ulong as LiveConnectExtension uses,
|
|
// so we don't end up with extra precision floating around
|
|
NSLiveConnectResult NSPluginInstance::lcGet(qulonglong objid, const QString& field)
|
|
{
|
|
NSLiveConnectResult result;
|
|
if (_scripting) {
|
|
KParts::LiveConnectExtension::Type type;
|
|
unsigned long outId;
|
|
result.success = _scripting->get(static_cast<unsigned long>(objid), field,
|
|
type, outId, result.value);
|
|
result.type = type;
|
|
result.objid = outId;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool NSPluginInstance::lcPut(qulonglong objid, const QString& field, const QString& value)
|
|
{
|
|
if (_scripting)
|
|
return _scripting->put(static_cast<unsigned long>(objid), field, value);
|
|
|
|
return false;
|
|
}
|
|
|
|
NSLiveConnectResult NSPluginInstance::lcCall(qulonglong objid, const QString& func,
|
|
const QStringList& args)
|
|
{
|
|
NSLiveConnectResult result;
|
|
if (_scripting) {
|
|
KParts::LiveConnectExtension::Type type;
|
|
unsigned long outId;
|
|
result.success = _scripting->call(static_cast<unsigned long>(objid), func, args,
|
|
type, outId, result.value);
|
|
result.type = type;
|
|
result.objid = outId;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void NSPluginInstance::lcUnregister(qulonglong objid)
|
|
{
|
|
if (_scripting)
|
|
_scripting->unregister(static_cast<unsigned long>(objid));
|
|
}
|
|
|
|
void NSPluginInstance::destroy()
|
|
{
|
|
if ( !_destroyed ) {
|
|
|
|
kDebug(1431) << "delete streams";
|
|
qDeleteAll( _waitingRequests );
|
|
|
|
while ( !_streams.isEmpty() ) {
|
|
NSPluginStreamBase *s = _streams.takeFirst();
|
|
s->stop();
|
|
delete s;
|
|
}
|
|
|
|
kDebug(1431) << "delete tempfiles";
|
|
qDeleteAll( _tempFiles );
|
|
|
|
kDebug(1431) << "delete callbacks";
|
|
delete _callback;
|
|
_callback = 0;
|
|
|
|
kDebug(1431) << "delete scripting";
|
|
delete _scripting;
|
|
_scripting = 0;
|
|
|
|
if (!_initializedOK) {
|
|
_destroyed = true;
|
|
return;
|
|
}
|
|
|
|
kDebug(1431) << "destroy plugin";
|
|
NPSavedData *saved = 0;
|
|
|
|
// As of 7/31/01, nsplugin crashes when used with Qt
|
|
// linked with libGL if the destroy function is called.
|
|
// A patch on that date hacked out the following call.
|
|
// On 11/17/01, Jeremy White has reenabled this destroy
|
|
// in a an attempt to better understand why this crash
|
|
// occurs so that the real problem can be found and solved.
|
|
// It's possible that a flaw in the SetWindow call
|
|
// caused the crash and it is now fixed.
|
|
if ( _pluginFuncs.destroy )
|
|
_pluginFuncs.destroy( _npp, &saved );
|
|
|
|
if (saved && saved->len && saved->buf)
|
|
g_NPN_MemFree(saved->buf);
|
|
if (saved)
|
|
g_NPN_MemFree(saved);
|
|
|
|
delete _pluginHost;
|
|
_pluginHost = 0;
|
|
|
|
if (_npp) {
|
|
::free(_npp); // matched with malloc() in newInstance
|
|
}
|
|
|
|
_destroyed = true;
|
|
}
|
|
}
|
|
|
|
|
|
void NSPluginInstance::shutdown()
|
|
{
|
|
NSPluginClass *cls = dynamic_cast<NSPluginClass*>(parent());
|
|
//destroy();
|
|
if (cls) {
|
|
cls->destroyInstance( this );
|
|
}
|
|
}
|
|
|
|
bool NSPluginInstance::hasPendingJSRequests() const
|
|
{
|
|
return _numJSRequests > 0;
|
|
}
|
|
|
|
void NSPluginInstance::timer()
|
|
{
|
|
if (!_embedded) {
|
|
_timer->setSingleShot( true );
|
|
_timer->start( 100 );
|
|
return;
|
|
}
|
|
|
|
//_streams.clear();
|
|
|
|
// start queued requests
|
|
kDebug(1431) << "looking for waiting requests";
|
|
while ( !_waitingRequests.isEmpty() ) {
|
|
kDebug(1431) << "request found";
|
|
Request req( *_waitingRequests.head() );
|
|
delete _waitingRequests.dequeue();
|
|
|
|
QString url;
|
|
|
|
// Note: sync javascript: handling with requestURL
|
|
|
|
// make absolute url
|
|
if ( req.url.left(11).toLower()=="javascript:" )
|
|
url = req.url;
|
|
else if ( KUrl::isRelativeUrl(req.url) ) {
|
|
KUrl bu( _baseURL );
|
|
KUrl absUrl( bu, req.url );
|
|
url = absUrl.url();
|
|
} else if ( req.url[0]=='/' && KUrl(_baseURL).hasHost() ) {
|
|
KUrl absUrl( _baseURL );
|
|
absUrl.setPath( req.url );
|
|
url = absUrl.url();
|
|
} else
|
|
url = req.url;
|
|
|
|
// non empty target = frame target
|
|
if ( !req.target.isEmpty())
|
|
{
|
|
if (_callback)
|
|
{
|
|
if ( req.post ) {
|
|
_callback->postURL( url, req.target, req.data, req.mime );
|
|
} else {
|
|
_callback->requestURL( url, req.target );
|
|
}
|
|
if ( req.notify ) {
|
|
NPURLNotify( req.url, NPRES_DONE, req.notify );
|
|
}
|
|
}
|
|
} else {
|
|
if (!url.isEmpty())
|
|
{
|
|
kDebug(1431) << "Starting new stream " << req.url;
|
|
|
|
if (req.post) {
|
|
// create stream
|
|
NSPluginStream *s = new NSPluginStream( this );
|
|
connect( s, SIGNAL(finished(NSPluginStreamBase*)),
|
|
SLOT(streamFinished(NSPluginStreamBase*)) );
|
|
_streams.append( s );
|
|
|
|
kDebug() << "posting to " << url;
|
|
|
|
emitStatus( i18n("Submitting data to %1", url) );
|
|
s->post( url, req.data, req.mime, req.notify, req.args, req.browserArgs );
|
|
} else if (url.toLower().startsWith("javascript:")){
|
|
if (_callback) {
|
|
static int _jsrequestid = 0;
|
|
_jsrequests.insert(_jsrequestid, new Request(req));
|
|
_callback->evalJavaScript(_jsrequestid++, url.mid(11));
|
|
} else {
|
|
--_numJSRequests;
|
|
kDebug() << "No callback for javascript: url!";
|
|
}
|
|
} else {
|
|
// create stream
|
|
NSPluginStream *s = new NSPluginStream( this );
|
|
connect( s, SIGNAL(finished(NSPluginStreamBase*)),
|
|
SLOT(streamFinished(NSPluginStreamBase*)) );
|
|
_streams.append( s );
|
|
|
|
kDebug() << "getting " << url;
|
|
|
|
emitStatus( i18n("Requesting %1", url) );
|
|
s->get( url, req.mime, req.notify, req.reload );
|
|
}
|
|
|
|
//break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
QString NSPluginInstance::normalizedURL(const QString& url) const {
|
|
|
|
// ### for dfaure: KUrl(KUrl("http://www.youtube.com/?v=JvOSnRD5aNk"), KUrl("javascript:window.location+"__flashplugin_unique__"));
|
|
|
|
//### hack, prolly evil, etc.
|
|
if (url.startsWith("javascript:"))
|
|
return url;
|
|
|
|
KUrl bu( _baseURL );
|
|
KUrl inURL(bu, url);
|
|
KConfig _cfg( "kcmnspluginrc" );
|
|
KConfigGroup cfg(&_cfg, "Misc");
|
|
|
|
if (!cfg.readEntry("HTTP URLs Only", false) ||
|
|
inURL.protocol() == "http" ||
|
|
inURL.protocol() == "https" ||
|
|
inURL.protocol() == "javascript") {
|
|
return inURL.url();
|
|
}
|
|
|
|
// Allow: javascript:, http, https, or no protocol (match loading)
|
|
kDebug(1431) << "NSPluginInstance::normalizedURL - I don't think so. http or https only!";
|
|
return QString();
|
|
}
|
|
|
|
|
|
void NSPluginInstance::requestURL( const QString &url, const QString &mime,
|
|
const QString &target, void *notify, bool forceNotify, bool reload )
|
|
{
|
|
// Generally this should already be done, but let's be safe for now.
|
|
QString nurl = normalizedURL(url);
|
|
if (nurl.isNull()) {
|
|
return;
|
|
}
|
|
|
|
// We dispatch JS events in target for empty target GET only.(see timer());
|
|
if (target.isEmpty() && nurl.left(11).toLower()=="javascript:")
|
|
++_numJSRequests;
|
|
|
|
kDebug(1431) << "NSPluginInstance::requestURL url=" << nurl << " target=" << target << " notify=" << notify << "JS jobs now:" << _numJSRequests;
|
|
_waitingRequests.enqueue( new Request( nurl, mime, target, notify, forceNotify, reload ) );
|
|
_timer->setSingleShot( true );
|
|
_timer->start( 100 );
|
|
}
|
|
|
|
|
|
void NSPluginInstance::postURL( const QString &url, const QByteArray& data,
|
|
const QString &mime,
|
|
const QString &target, void *notify,
|
|
const KParts::OpenUrlArguments& args,
|
|
const KParts::BrowserArguments& browserArgs,
|
|
bool forceNotify )
|
|
{
|
|
// Generally this should already be done, but let's be safe for now.
|
|
QString nurl = normalizedURL(url);
|
|
if (nurl.isNull()) {
|
|
return;
|
|
}
|
|
|
|
kDebug(1431) << "NSPluginInstance::postURL url=" << nurl << " target=" << target << " notify=" << notify;
|
|
_waitingRequests.enqueue( new Request( nurl, data, mime, target, notify, args, browserArgs, forceNotify) );
|
|
_timer->setSingleShot( true );
|
|
_timer->start( 100 );
|
|
}
|
|
|
|
|
|
void NSPluginInstance::emitStatus(const QString &message)
|
|
{
|
|
if( _callback )
|
|
_callback->statusMessage( message );
|
|
}
|
|
|
|
|
|
void NSPluginInstance::streamFinished( NSPluginStreamBase* strm )
|
|
{
|
|
kDebug(1431) << "-> NSPluginInstance::streamFinished";
|
|
emitStatus( QString() );
|
|
_streams.removeOne(strm);
|
|
strm->deleteLater();
|
|
_timer->setSingleShot( true );
|
|
_timer->start( 100 );
|
|
}
|
|
|
|
void NSPluginInstance::setupWindow(int winId, int w, int h)
|
|
{
|
|
kDebug(1431) << "-> NSPluginInstance::setupWindow( winid =" << winId << " w=" << w << ", h=" << h << " ) ";
|
|
if (_pluginHost)
|
|
_pluginHost->setupWindow(winId, w, h);
|
|
else
|
|
kWarning(1431) << "No plugin host!";
|
|
|
|
kDebug(1431) << "<- NSPluginInstance::setupWindow";
|
|
_width = w;
|
|
_height = h;
|
|
_embedded = true;
|
|
}
|
|
|
|
void NSPluginInstance::resizePlugin(int clientWinId, int w, int h)
|
|
{
|
|
kDebug() << _width << w << _height << h << _embedded;
|
|
if (!_embedded)
|
|
return;
|
|
if (w == _width && h == _height)
|
|
return;
|
|
_pluginHost->resizePlugin(clientWinId, w, h);
|
|
_width = w;
|
|
_height = h;
|
|
}
|
|
|
|
|
|
void NSPluginInstance::javascriptResult(int id, const QString &result) {
|
|
QMap<int, Request*>::iterator i = _jsrequests.find( id );
|
|
if (i != _jsrequests.end()) {
|
|
--_numJSRequests;
|
|
|
|
Request *req = i.value();
|
|
_jsrequests.erase( i );
|
|
NSPluginStream *s = new NSPluginStream( this );
|
|
connect( s, SIGNAL(finished(NSPluginStreamBase*)),
|
|
SLOT(streamFinished(NSPluginStreamBase*)) );
|
|
_streams.append( s );
|
|
|
|
int len = result.length();
|
|
s->create( req->url, QString("text/plain"), req->notify, req->forceNotify );
|
|
kDebug(1431) << "javascriptResult has been called with: "<<result << "num JS requests now:" << _numJSRequests;
|
|
if (len > 0) {
|
|
QByteArray data(len + 1, 0);
|
|
memcpy(data.data(), result.toLatin1(), len);
|
|
data[len] = 0;
|
|
s->process(data, 0);
|
|
} else {
|
|
len = 7; // "unknown"
|
|
QByteArray data(len + 1, 0);
|
|
memcpy(data.data(), "unknown", len);
|
|
data[len] = 0;
|
|
s->process(data, 0);
|
|
}
|
|
s->finish(false);
|
|
|
|
delete req;
|
|
}
|
|
}
|
|
|
|
|
|
NPError NSPluginInstance::NPGetValue(NPPVariable variable, void *value)
|
|
{
|
|
if( value==0 ) {
|
|
kDebug() << "FIXME: value==0 in NSPluginInstance::NPGetValue";
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
if (!_pluginFuncs.getvalue)
|
|
return NPERR_GENERIC_ERROR;
|
|
|
|
NPError error = _pluginFuncs.getvalue(_npp, variable, value);
|
|
|
|
CHECK(GetValue,error);
|
|
}
|
|
|
|
|
|
NPError NSPluginInstance::NPSetValue(NPNVariable variable, void *value)
|
|
{
|
|
if( value==0 ) {
|
|
kDebug() << "FIXME: value==0 in NSPluginInstance::NPSetValue";
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
if (!_pluginFuncs.setvalue)
|
|
return NPERR_GENERIC_ERROR;
|
|
|
|
NPError error = _pluginFuncs.setvalue(_npp, variable, value);
|
|
|
|
CHECK(SetValue,error);
|
|
}
|
|
|
|
|
|
NPError NSPluginInstance::NPSetWindow(NPWindow *window)
|
|
{
|
|
if( window==0 ) {
|
|
kDebug() << "FIXME: window==0 in NSPluginInstance::NPSetWindow";
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
if (!_pluginFuncs.setwindow)
|
|
return NPERR_GENERIC_ERROR;
|
|
|
|
NPError error = _pluginFuncs.setwindow(_npp, window);
|
|
|
|
CHECK(SetWindow,error);
|
|
}
|
|
|
|
|
|
NPError NSPluginInstance::NPDestroyStream(NPStream *stream, NPReason reason)
|
|
{
|
|
if( stream==0 ) {
|
|
kDebug() << "FIXME: stream==0 in NSPluginInstance::NPDestroyStream";
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
if (!_pluginFuncs.destroystream)
|
|
return NPERR_GENERIC_ERROR;
|
|
|
|
NPError error = _pluginFuncs.destroystream(_npp, stream, reason);
|
|
|
|
CHECK(DestroyStream,error);
|
|
}
|
|
|
|
|
|
NPError NSPluginInstance::NPNewStream(NPMIMEType type, NPStream *stream, NPBool seekable, uint16_t *stype)
|
|
{
|
|
if( stream==0 ) {
|
|
kDebug() << "FIXME: stream==0 in NSPluginInstance::NPNewStream";
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
if( stype==0 ) {
|
|
kDebug() << "FIXME: stype==0 in NSPluginInstance::NPNewStream";
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
if (!_pluginFuncs.newstream)
|
|
return NPERR_GENERIC_ERROR;
|
|
|
|
NPError error = _pluginFuncs.newstream(_npp, type, stream, seekable, stype);
|
|
|
|
CHECK(NewStream,error);
|
|
}
|
|
|
|
|
|
void NSPluginInstance::NPStreamAsFile(NPStream *stream, const char *fname)
|
|
{
|
|
if( stream==0 ) {
|
|
kDebug() << "FIXME: stream==0 in NSPluginInstance::NPStreamAsFile";
|
|
return;
|
|
}
|
|
|
|
if( fname==0 ) {
|
|
kDebug() << "FIXME: fname==0 in NSPluginInstance::NPStreamAsFile";
|
|
return;
|
|
}
|
|
|
|
if (!_pluginFuncs.asfile)
|
|
return;
|
|
|
|
_pluginFuncs.asfile(_npp, stream, fname);
|
|
}
|
|
|
|
|
|
int32_t NSPluginInstance::NPWrite(NPStream *stream, int32_t offset, int32_t len, void *buf)
|
|
{
|
|
if( stream==0 ) {
|
|
kDebug() << "FIXME: stream==0 in NSPluginInstance::NPWrite";
|
|
return 0;
|
|
}
|
|
|
|
if( buf==0 ) {
|
|
kDebug() << "FIXME: buf==0 in NSPluginInstance::NPWrite";
|
|
return 0;
|
|
}
|
|
|
|
if (!_pluginFuncs.write)
|
|
return 0;
|
|
|
|
return _pluginFuncs.write(_npp, stream, offset, len, buf);
|
|
}
|
|
|
|
|
|
int32_t NSPluginInstance::NPWriteReady(NPStream *stream)
|
|
{
|
|
if( stream==0 ) {
|
|
kDebug() << "FIXME: stream==0 in NSPluginInstance::NPWriteReady";
|
|
return 0;
|
|
}
|
|
|
|
if (!_pluginFuncs.writeready)
|
|
return 0;
|
|
|
|
return _pluginFuncs.writeready(_npp, stream);
|
|
}
|
|
|
|
|
|
void NSPluginInstance::NPURLNotify(const QString &url, NPReason reason, void *notifyData)
|
|
{
|
|
if (!_pluginFuncs.urlnotify)
|
|
return;
|
|
|
|
_pluginFuncs.urlnotify(_npp, url.toAscii(), reason, notifyData);
|
|
}
|
|
|
|
|
|
void NSPluginInstance::addTempFile(KTemporaryFile *tmpFile)
|
|
{
|
|
_tempFiles.append(tmpFile);
|
|
}
|
|
|
|
static bool has_focus = false;
|
|
|
|
void NSPluginInstance::gotFocusIn()
|
|
{
|
|
has_focus = true;
|
|
}
|
|
|
|
void NSPluginInstance::gotFocusOut()
|
|
{
|
|
has_focus = false;
|
|
}
|
|
|
|
#include <dlfcn.h>
|
|
// Prevent plugins from polling the keyboard regardless of focus.
|
|
static int (*real_xquerykeymap)( Display*, char[32] ) = NULL;
|
|
|
|
extern "C" KDE_EXPORT
|
|
int XQueryKeymap( Display* dpy, char k[32] )
|
|
{
|
|
if( real_xquerykeymap == NULL )
|
|
real_xquerykeymap = (int (*)( Display*, char[32] )) dlsym( RTLD_NEXT, "XQueryKeymap" );
|
|
if( has_focus )
|
|
return real_xquerykeymap( dpy, k );
|
|
memset( k, 0, 32 );
|
|
return 1;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
NSPluginViewer::NSPluginViewer( QObject *parent )
|
|
: QObject( parent )
|
|
{
|
|
(void) new ViewerAdaptor( this );
|
|
QDBusConnection::sessionBus().registerObject( "/Viewer", this );
|
|
|
|
QObject::connect(QDBusConnection::sessionBus().interface(),
|
|
SIGNAL(serviceOwnerChanged(QString,QString,QString)),
|
|
this, SLOT(appChanged(QString,QString,QString)));
|
|
}
|
|
|
|
|
|
NSPluginViewer::~NSPluginViewer()
|
|
{
|
|
kDebug(1431) << "NSPluginViewer::~NSPluginViewer";
|
|
}
|
|
|
|
|
|
void NSPluginViewer::appChanged( const QString& id, const QString& oldOwner, const QString& newOwner) {
|
|
Q_UNUSED(id);
|
|
|
|
if ( oldOwner.isEmpty() || !newOwner.isEmpty() ) // only care about unregistering apps
|
|
return;
|
|
|
|
QMap<QString, NSPluginClass*>::iterator it = _classes.begin();
|
|
const QMap<QString, NSPluginClass*>::iterator end = _classes.end();
|
|
for ( ; it != end; ++it )
|
|
{
|
|
if (it.value()->app() == oldOwner) {
|
|
it = _classes.erase(it);
|
|
}
|
|
}
|
|
|
|
if (_classes.isEmpty()) {
|
|
shutdown();
|
|
}
|
|
}
|
|
|
|
|
|
void NSPluginViewer::shutdown()
|
|
{
|
|
kDebug(1431) << "NSPluginViewer::shutdown";
|
|
_classes.clear();
|
|
qApp->quit();
|
|
}
|
|
|
|
|
|
QDBusObjectPath NSPluginViewer::newClass( const QString& plugin, const QString& senderId )
|
|
{
|
|
kDebug(1431) << "NSPluginViewer::NewClass( " << plugin << ")";
|
|
|
|
// search existing class
|
|
NSPluginClass *cls = _classes.value( plugin );
|
|
if ( !cls ) {
|
|
// create new class
|
|
cls = new NSPluginClass( plugin, this );
|
|
cls->setApp(senderId.toLatin1());
|
|
if ( cls->error() ) {
|
|
kError(1431) << "Can't create plugin class" << endl;
|
|
delete cls;
|
|
return QDBusObjectPath("/null");
|
|
}
|
|
|
|
_classes.insert( plugin, cls );
|
|
}
|
|
|
|
return QDBusObjectPath(cls->objectName());
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
static int s_classCounter = 0;
|
|
|
|
bool NSPluginClass::s_initedGTK = false;
|
|
|
|
typedef void gtkInitFunc(int *argc, char ***argv);
|
|
|
|
NSPluginClass::NSPluginClass( const QString &library,
|
|
QObject *parent )
|
|
: QObject( parent )
|
|
{
|
|
(void) new ClassAdaptor( this );
|
|
// The object name is used to store the dbus object path
|
|
setObjectName( QLatin1String( "/Class_" ) + QString::number( ++s_classCounter ) );
|
|
QDBusConnection::sessionBus().registerObject( objectName(), this );
|
|
|
|
// initialize members
|
|
_handle = new KLibrary(QFile::encodeName(library), KGlobal::mainComponent(), this);
|
|
_libname = library;
|
|
_constructed = false;
|
|
_error = true;
|
|
_NP_GetMIMEDescription = 0;
|
|
_NP_Initialize = 0;
|
|
_NP_Shutdown = 0;
|
|
|
|
_timer = new QTimer( this );
|
|
connect( _timer, SIGNAL(timeout()), SLOT(timer()) );
|
|
|
|
// check lib handle
|
|
if (!_handle->load()) {
|
|
kDebug(1431) << "Could not dlopen " << library;
|
|
return;
|
|
}
|
|
|
|
// get exported lib functions
|
|
_NP_GetMIMEDescription = (NP_GetMIMEDescriptionUPP *)_handle->resolveFunction("NP_GetMIMEDescription");
|
|
_NP_Initialize = (NP_InitializeUPP *)_handle->resolveFunction("NP_Initialize");
|
|
_NP_Shutdown = (NP_ShutdownUPP *)_handle->resolveFunction("NP_Shutdown");
|
|
|
|
// check for valid returned ptrs
|
|
if (!_NP_GetMIMEDescription) {
|
|
kDebug(1431) << "Could not get symbol NP_GetMIMEDescription";
|
|
return;
|
|
}
|
|
|
|
if (!_NP_Initialize) {
|
|
kDebug(1431) << "Could not get symbol NP_Initialize";
|
|
return;
|
|
}
|
|
|
|
if (!_NP_Shutdown) {
|
|
kDebug(1431) << "Could not get symbol NP_Shutdown";
|
|
return;
|
|
}
|
|
|
|
// initialize plugin
|
|
kDebug(1431) << "Plugin library " << library << " loaded!";
|
|
|
|
// see if it uses gtk
|
|
if (!s_initedGTK) {
|
|
gtkInitFunc* gtkInit = (gtkInitFunc*)_handle->resolveFunction("gtk_init");
|
|
if (gtkInit) {
|
|
kDebug(1431) << "Calling gtk_init for the plugin";
|
|
// Prevent gtk_init() from replacing the X error handlers, since the Gtk
|
|
// handlers abort when they receive an X error, thus killing the viewer.
|
|
int (*old_error_handler)(Display*,XErrorEvent*) = XSetErrorHandler(0);
|
|
int (*old_io_error_handler)(Display*) = XSetIOErrorHandler(0);
|
|
gtkInit(0, 0);
|
|
XSetErrorHandler(old_error_handler);
|
|
XSetIOErrorHandler(old_io_error_handler);
|
|
s_initedGTK = true;
|
|
}
|
|
}
|
|
|
|
_constructed = true;
|
|
_error = initialize()!=NPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
NSPluginClass::~NSPluginClass()
|
|
{
|
|
qDeleteAll( _instances );
|
|
qDeleteAll( _trash );
|
|
|
|
shutdown();
|
|
if (_handle)
|
|
_handle->unload();
|
|
}
|
|
|
|
|
|
void NSPluginClass::timer()
|
|
{
|
|
// delete instances
|
|
while ( !_trash.isEmpty() ) {
|
|
NSPluginInstance *it = _trash.takeFirst();
|
|
int i = _instances.indexOf(it);
|
|
if ( i != -1 )
|
|
delete _instances.takeAt(i);
|
|
else // there should be no instansces in trash, which are not in _instances
|
|
delete it;
|
|
}
|
|
}
|
|
|
|
|
|
int NSPluginClass::initialize()
|
|
{
|
|
kDebug(1431) << "NSPluginClass::Initialize()";
|
|
|
|
if ( !_constructed )
|
|
return NPERR_GENERIC_ERROR;
|
|
|
|
// initialize nescape exported functions
|
|
memset(&_pluginFuncs, 0, sizeof(_pluginFuncs));
|
|
memset(&_nsFuncs, 0, sizeof(_nsFuncs));
|
|
|
|
_pluginFuncs.size = sizeof(_pluginFuncs);
|
|
_nsFuncs.size = sizeof(_nsFuncs);
|
|
_nsFuncs.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
|
|
_nsFuncs.geturl = g_NPN_GetURL;
|
|
_nsFuncs.posturl = g_NPN_PostURL;
|
|
_nsFuncs.requestread = g_NPN_RequestRead;
|
|
_nsFuncs.newstream = g_NPN_NewStream;
|
|
_nsFuncs.write = g_NPN_Write;
|
|
_nsFuncs.destroystream = g_NPN_DestroyStream;
|
|
_nsFuncs.status = g_NPN_Status;
|
|
_nsFuncs.uagent = g_NPN_UserAgent;
|
|
_nsFuncs.memalloc = g_NPN_MemAlloc;
|
|
_nsFuncs.memfree = g_NPN_MemFree;
|
|
_nsFuncs.memflush = g_NPN_MemFlush;
|
|
_nsFuncs.reloadplugins = g_NPN_ReloadPlugins;
|
|
_nsFuncs.getJavaEnv = g_NPN_GetJavaEnv;
|
|
_nsFuncs.getJavaPeer = g_NPN_GetJavaPeer;
|
|
_nsFuncs.geturlnotify = g_NPN_GetURLNotify;
|
|
_nsFuncs.posturlnotify = g_NPN_PostURLNotify;
|
|
_nsFuncs.getvalue = g_NPN_GetValue;
|
|
_nsFuncs.setvalue = g_NPN_SetValue;
|
|
_nsFuncs.invalidaterect = g_NPN_InvalidateRect;
|
|
_nsFuncs.invalidateregion = g_NPN_InvalidateRegion;
|
|
_nsFuncs.forceredraw = g_NPN_ForceRedraw;
|
|
|
|
ScriptExportEngine::fillInScriptingFunctions(&_nsFuncs);
|
|
|
|
_nsFuncs.pushpopupsenabledstate = g_NPN_PushPopupsEnabledState;
|
|
_nsFuncs.poppopupsenabledstate = g_NPN_PopPopupsEnabledState;
|
|
|
|
// initialize plugin
|
|
NPError error = _NP_Initialize(&_nsFuncs, &_pluginFuncs);
|
|
assert(_nsFuncs.size == sizeof(_nsFuncs));
|
|
CHECK(Initialize,error);
|
|
}
|
|
|
|
|
|
QString NSPluginClass::getMIMEDescription()
|
|
{
|
|
return _NP_GetMIMEDescription();
|
|
}
|
|
|
|
|
|
void NSPluginClass::shutdown()
|
|
{
|
|
kDebug(1431) << "NSPluginClass::shutdown error=" << _error;
|
|
if( _NP_Shutdown && !_error )
|
|
_NP_Shutdown();
|
|
}
|
|
|
|
|
|
QDBusObjectPath NSPluginClass::newInstance( const QString &url, const QString &mimeType, bool embed,
|
|
const QStringList &argn, const QStringList &argv,
|
|
const QString &appId, const QString &callbackId, bool reload )
|
|
{
|
|
kDebug(1431) << url << mimeType;
|
|
|
|
if ( !_constructed )
|
|
return QDBusObjectPath("/null");
|
|
|
|
// Create plugin instance object
|
|
NSPluginInstance *inst = new NSPluginInstance( &_pluginFuncs, _handle,
|
|
url, mimeType, argn, argv,
|
|
appId, callbackId, embed, this );
|
|
if ( !inst->wasInitializedOK() ) {
|
|
delete inst;
|
|
return QDBusObjectPath("/null");
|
|
}
|
|
|
|
// create source stream
|
|
if ( !url.isEmpty() )
|
|
inst->requestURL( url, mimeType, QString(), 0, false, reload );
|
|
|
|
_instances.append( inst );
|
|
return QDBusObjectPath(inst->objectName());
|
|
}
|
|
|
|
|
|
void NSPluginClass::destroyInstance( NSPluginInstance* inst )
|
|
{
|
|
// be sure we don't deal with a dangling pointer
|
|
if ( NSPluginInstance::lastPluginInstance() == inst )
|
|
NSPluginInstance::setLastPluginInstance(0);
|
|
|
|
// mark for destruction
|
|
_trash.append( inst );
|
|
timer(); //_timer->start( 0, TRUE );
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
NSPluginStreamBase::NSPluginStreamBase( NSPluginInstance *instance )
|
|
: QObject( instance ), _instance(instance), _stream(0), _tempFile(0L),
|
|
_pos(0), _queuePos(0), _error(false)
|
|
{
|
|
_informed = false;
|
|
}
|
|
|
|
|
|
NSPluginStreamBase::~NSPluginStreamBase()
|
|
{
|
|
if (_stream) {
|
|
_instance->NPDestroyStream( _stream, NPRES_USER_BREAK );
|
|
if (_stream && _stream->url)
|
|
free(const_cast<char*>(_stream->url));
|
|
delete _stream;
|
|
_stream = 0;
|
|
}
|
|
|
|
delete _tempFile;
|
|
_tempFile = 0;
|
|
}
|
|
|
|
|
|
void NSPluginStreamBase::stop()
|
|
{
|
|
finish( true );
|
|
}
|
|
|
|
void NSPluginStreamBase::inform()
|
|
{
|
|
|
|
if (! _informed)
|
|
{
|
|
KUrl src(_url);
|
|
|
|
_informed = true;
|
|
|
|
// inform the plugin
|
|
_instance->NPNewStream( _mimeType.isEmpty() ? (char *) "text/plain" : (char*)_mimeType.data(),
|
|
_stream, false, &_streamType );
|
|
kDebug(1431) << "NewStream stype=" << _streamType << " url=" << _url << " mime=" << _mimeType;
|
|
|
|
// prepare data transfer
|
|
_tempFile = 0L;
|
|
|
|
if ( _streamType==NP_ASFILE || _streamType==NP_ASFILEONLY ) {
|
|
_onlyAsFile = _streamType==NP_ASFILEONLY;
|
|
if ( KUrl(_url).isLocalFile() ) {
|
|
kDebug(1431) << "local file";
|
|
// local file can be passed directly
|
|
_fileURL = KUrl(_url).toLocalFile();
|
|
|
|
// without streaming stream is finished already
|
|
if ( _onlyAsFile ) {
|
|
kDebug() << "local file AS_FILE_ONLY";
|
|
finish( false );
|
|
}
|
|
} else {
|
|
kDebug() << "remote file";
|
|
|
|
// stream into temporary file (use lower() in case the
|
|
// filename as an upper case X in it)
|
|
_tempFile = new KTemporaryFile;
|
|
_tempFile->open();
|
|
_fileURL = _tempFile->fileName();
|
|
kDebug() << "saving into " << _fileURL;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
bool NSPluginStreamBase::create( const QString& url, const QString& mimeType, void *notify, bool forceNotify)
|
|
{
|
|
if ( _stream )
|
|
return false;
|
|
|
|
_url = url;
|
|
_notifyData = notify;
|
|
_pos = 0;
|
|
_tries = 0;
|
|
_onlyAsFile = false;
|
|
_streamType = NP_NORMAL;
|
|
_informed = false;
|
|
_forceNotify = forceNotify;
|
|
|
|
// create new stream
|
|
_stream = new NPStream;
|
|
_stream->ndata = this;
|
|
_stream->url = strdup(url.toAscii());
|
|
_stream->end = 0;
|
|
_stream->pdata = 0;
|
|
_stream->lastmodified = 0;
|
|
_stream->notifyData = _notifyData;
|
|
_stream->headers = 0;
|
|
|
|
_mimeType = mimeType;
|
|
|
|
return true;
|
|
}
|
|
|
|
void NSPluginStreamBase::updateURL( const KUrl& newURL )
|
|
{
|
|
_url = newURL;
|
|
free(const_cast<char*>(_stream->url));
|
|
_stream->url = strdup(_url.url().toLatin1().data());
|
|
}
|
|
|
|
int NSPluginStreamBase::process( const QByteArray &data, int start )
|
|
{
|
|
int32_t max, sent, to_sent, len;
|
|
#ifdef __GNUC__
|
|
#warning added a const_cast
|
|
#endif
|
|
char *d = const_cast<char*>(data.data()) + start;
|
|
|
|
to_sent = data.size() - start;
|
|
while (to_sent > 0)
|
|
{
|
|
inform();
|
|
|
|
max = _instance->NPWriteReady(_stream);
|
|
//kDebug(1431) << "to_sent == " << to_sent << " and max = " << max;
|
|
len = qMin(max, to_sent);
|
|
|
|
//kDebug(1431) << "-> Feeding stream to plugin: offset=" << _pos << ", len=" << len;
|
|
sent = _instance->NPWrite( _stream, _pos, len, d );
|
|
//kDebug(1431) << "<- Feeding stream: sent = " << sent;
|
|
|
|
if (sent == 0) // interrupt the stream for a few ms
|
|
break;
|
|
|
|
if (sent < 0) {
|
|
// stream data rejected/error
|
|
kDebug(1431) << "stream data rejected/error";
|
|
_error = true;
|
|
break;
|
|
}
|
|
|
|
if (_tempFile) {
|
|
_tempFile->write(d, sent);
|
|
}
|
|
|
|
to_sent -= sent;
|
|
_pos += sent;
|
|
d += sent;
|
|
}
|
|
|
|
return data.size() - to_sent;
|
|
}
|
|
|
|
|
|
bool NSPluginStreamBase::pump()
|
|
{
|
|
//kDebug(1431) << "queue pos " << _queuePos << ", size " << _queue.size();
|
|
|
|
inform();
|
|
|
|
// Suspend until JS handled..
|
|
if (_instance->hasPendingJSRequests())
|
|
return false;
|
|
|
|
if ( _queuePos<_queue.size() ) {
|
|
int newPos;
|
|
|
|
// handle AS_FILE_ONLY streams
|
|
if ( _onlyAsFile ) {
|
|
if (_tempFile) {
|
|
_tempFile->write( _queue, _queue.size() );
|
|
}
|
|
newPos = _queuePos+_queue.size();
|
|
} else {
|
|
// normal streams
|
|
newPos = process( _queue, _queuePos );
|
|
}
|
|
|
|
// count tries
|
|
if ( newPos==_queuePos )
|
|
_tries++;
|
|
else
|
|
_tries = 0;
|
|
|
|
_queuePos = newPos;
|
|
}
|
|
|
|
// return true if queue finished
|
|
return _queuePos>=_queue.size();
|
|
}
|
|
|
|
|
|
void NSPluginStreamBase::queue( const QByteArray &data )
|
|
{
|
|
_queue = data;
|
|
_queue.detach();
|
|
_queuePos = 0;
|
|
_tries = 0;
|
|
|
|
/*
|
|
kDebug(1431) << "new queue size=" << data.size()
|
|
<< " data=" << (void*)data.data()
|
|
<< " queue=" << (void*)_queue.data() << " qsize="
|
|
<< _queue.size() << endl;
|
|
*/
|
|
}
|
|
|
|
|
|
void NSPluginStreamBase::finish( bool err )
|
|
{
|
|
kDebug(1431) << "finish error=" << err;
|
|
|
|
_queue.resize( 0 );
|
|
_pos = 0;
|
|
_queuePos = 0;
|
|
|
|
inform();
|
|
|
|
if ( !err ) {
|
|
if ( _tempFile ) {
|
|
_tempFile->close();
|
|
_instance->addTempFile( _tempFile );
|
|
_tempFile = 0;
|
|
}
|
|
|
|
if ( !_fileURL.isEmpty() ) {
|
|
kDebug() << "stream as file " << _fileURL;
|
|
_instance->NPStreamAsFile( _stream, _fileURL.toAscii() );
|
|
}
|
|
|
|
_instance->NPDestroyStream( _stream, NPRES_DONE );
|
|
if (_notifyData || _forceNotify)
|
|
_instance->NPURLNotify( _url.url(), NPRES_DONE, _notifyData );
|
|
} else {
|
|
// close temp file
|
|
if ( _tempFile ) {
|
|
_tempFile->close();
|
|
}
|
|
|
|
// destroy stream
|
|
_instance->NPDestroyStream( _stream, NPRES_NETWORK_ERR );
|
|
if (_notifyData || _forceNotify)
|
|
_instance->NPURLNotify( _url.url(), NPRES_NETWORK_ERR, _notifyData );
|
|
}
|
|
|
|
// delete stream
|
|
if (_stream && _stream->url)
|
|
free(const_cast<char *>(_stream->url));
|
|
delete _stream;
|
|
_stream = 0;
|
|
|
|
// destroy NSPluginStream object
|
|
emit finished( this );
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
NSPluginBufStream::NSPluginBufStream( class NSPluginInstance *instance )
|
|
: NSPluginStreamBase( instance )
|
|
{
|
|
_timer = new QTimer( this );
|
|
connect( _timer, SIGNAL(timeout()), this, SLOT(timer()) );
|
|
}
|
|
|
|
|
|
NSPluginBufStream::~NSPluginBufStream()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
bool NSPluginBufStream::get( const QString& url, const QString& mimeType,
|
|
const QByteArray &buf, void *notifyData,
|
|
bool singleShot )
|
|
{
|
|
_singleShot = singleShot;
|
|
if ( create( url, mimeType, notifyData ) ) {
|
|
queue( buf );
|
|
_timer->setSingleShot( true );
|
|
_timer->start( 100 );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void NSPluginBufStream::timer()
|
|
{
|
|
bool finished = pump();
|
|
if ( _singleShot )
|
|
finish( false );
|
|
else {
|
|
|
|
if ( !finished && tries()<=8 ) {
|
|
_timer->setSingleShot( true );
|
|
_timer->start( 100 );
|
|
} else
|
|
finish( error() || tries()>8 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
NSPluginStream::NSPluginStream( NSPluginInstance *instance )
|
|
: NSPluginStreamBase( instance ), _job(0)
|
|
{
|
|
_resumeTimer = new QTimer( this );
|
|
connect(_resumeTimer, SIGNAL(timeout()), this, SLOT(resume()));
|
|
}
|
|
|
|
|
|
NSPluginStream::~NSPluginStream()
|
|
{
|
|
if ( _job )
|
|
_job->kill( KJob::Quietly );
|
|
}
|
|
|
|
|
|
bool NSPluginStream::get( const QString& url, const QString& mimeType,
|
|
void *notify, bool reload )
|
|
{
|
|
// create new stream
|
|
if ( create( url, mimeType, notify ) ) {
|
|
// start the kio job
|
|
_job = KIO::get(KUrl( url ), KIO::NoReload, KIO::HideProgressInfo);
|
|
_job->addMetaData("errorPage", "false");
|
|
_job->addMetaData("AllowCompressedPage", "false");
|
|
_job->addMetaData("PropagateHttpHeader", "true");
|
|
if (reload) {
|
|
_job->addMetaData("cache", "reload");
|
|
}
|
|
connect(_job, SIGNAL(data(KIO::Job*,QByteArray)),
|
|
SLOT(data(KIO::Job*,QByteArray)));
|
|
connect(_job, SIGNAL(result(KJob*)), SLOT(result(KJob*)));
|
|
connect(_job, SIGNAL(totalSize(KJob*,qulonglong)),
|
|
SLOT(totalSize(KJob*,qulonglong)));
|
|
connect(_job, SIGNAL(mimetype(KIO::Job*,QString)),
|
|
SLOT(mimetype(KIO::Job*,QString)));
|
|
connect(_job, SIGNAL(redirection(KIO::Job*,KUrl)),
|
|
SLOT(redirection(KIO::Job*,KUrl)));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool NSPluginStream::post( const QString& url, const QByteArray& data,
|
|
const QString& mimeType, void *notify, const KParts::OpenUrlArguments& args,
|
|
const KParts::BrowserArguments& browserArgs )
|
|
{
|
|
Q_UNUSED( args )
|
|
// create new stream
|
|
if ( create( url, mimeType, notify ) ) {
|
|
// start the kio job
|
|
_job = KIO::http_post(KUrl( url ), data, KIO::HideProgressInfo);
|
|
_job->addMetaData("content-type", browserArgs.contentType());
|
|
_job->addMetaData("errorPage", "false");
|
|
_job->addMetaData("PropagateHttpHeader", "true");
|
|
_job->addMetaData("AllowCompressedPage", "false");
|
|
connect(_job, SIGNAL(data(KIO::Job*,QByteArray)),
|
|
SLOT(data(KIO::Job*,QByteArray)));
|
|
connect(_job, SIGNAL(result(KJob*)), SLOT(result(KJob*)));
|
|
connect(_job, SIGNAL(totalSize(KJob*,qulonglong)),
|
|
SLOT(totalSize(KJob*,qulonglong)));
|
|
connect(_job, SIGNAL(mimetype(KIO::Job*,QString)),
|
|
SLOT(mimetype(KIO::Job*,QString)));
|
|
connect(_job, SIGNAL(redirection(KIO::Job*,KUrl)),
|
|
SLOT(redirection(KIO::Job*,KUrl)));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void NSPluginStream::data(KIO::Job*, const QByteArray &data)
|
|
{
|
|
//kDebug(1431) << "NSPluginStream::data - job=" << (void*)job << " data size=" << data.size();
|
|
queue( data );
|
|
if ( !pump() ) {
|
|
_job->suspend();
|
|
_resumeTimer->setSingleShot( true );
|
|
_resumeTimer->start( 100 );
|
|
}
|
|
}
|
|
|
|
void NSPluginStream::redirection(KIO::Job * /*job*/, const KUrl& url)
|
|
{
|
|
updateURL(url);
|
|
}
|
|
|
|
void NSPluginStream::totalSize(KJob * job, qulonglong size)
|
|
{
|
|
kDebug(1431) << "NSPluginStream::totalSize - job=" << (void*)job << " size=" << KIO::number(size);
|
|
_stream->end = size;
|
|
}
|
|
|
|
void NSPluginStream::mimetype(KIO::Job * job, const QString &mimeType)
|
|
{
|
|
kDebug(1431) << "NSPluginStream::QByteArray - job=" << (void*)job << " mimeType=" << mimeType;
|
|
_mimeType = mimeType;
|
|
_headers = job->metaData()["HTTP-Headers"].toLatin1();
|
|
_stream->headers = _headers.data();
|
|
}
|
|
|
|
void NSPluginStream::resume()
|
|
{
|
|
if ( error() || tries()>8 ) {
|
|
_job->kill( KJob::Quietly );
|
|
finish( true );
|
|
return;
|
|
}
|
|
|
|
if ( pump() ) {
|
|
kDebug(1431) << "resume job";
|
|
_job->resume();
|
|
} else {
|
|
kDebug(1431) << "restart timer";
|
|
_resumeTimer->setSingleShot( true );
|
|
_resumeTimer->start( 100 );
|
|
}
|
|
}
|
|
|
|
|
|
void NSPluginStream::result(KJob *job)
|
|
{
|
|
int err = job->error();
|
|
_job = 0;
|
|
finish( err!=0 || error() );
|
|
}
|
|
|
|
#include "nsplugin.moc"
|
|
// vim: ts=4 sw=4 et
|
|
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;
|