summaryrefslogtreecommitdiff
path: root/extensions/source/plugin/unx
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/source/plugin/unx')
-rw-r--r--extensions/source/plugin/unx/makefile.mk110
-rw-r--r--extensions/source/plugin/unx/mediator.cxx309
-rw-r--r--extensions/source/plugin/unx/npnapi.cxx898
-rw-r--r--extensions/source/plugin/unx/nppapi.cxx602
-rw-r--r--extensions/source/plugin/unx/npwrap.cxx513
-rw-r--r--extensions/source/plugin/unx/plugcon.cxx282
-rw-r--r--extensions/source/plugin/unx/sysplug.cxx131
-rw-r--r--extensions/source/plugin/unx/unxmgr.cxx315
8 files changed, 3160 insertions, 0 deletions
diff --git a/extensions/source/plugin/unx/makefile.mk b/extensions/source/plugin/unx/makefile.mk
new file mode 100644
index 000000000000..669aaa556e62
--- /dev/null
+++ b/extensions/source/plugin/unx/makefile.mk
@@ -0,0 +1,110 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+PRJ=..$/..$/..
+
+PRJNAME=extensions
+TARGET=plunx
+TARGETTYPE=CUI
+ENABLE_EXCEPTIONS=TRUE
+
+.INCLUDE : ..$/util$/makefile.pmk
+
+.IF "$(GUIBASE)"=="aqua"
+dummy:
+ @echo "Nothing to build for GUIBASE aqua."
+
+.ELSE
+
+# --- Files --------------------------------------------------------
+
+INCPRE+=-I$(SOLARINCDIR)$/mozilla$/plugin
+.IF "$(SOLAR_JAVA)" != ""
+INCPRE+=-I$(SOLARINCDIR)$/mozilla$/java
+INCPRE+=-I$(SOLARINCDIR)$/mozilla$/nspr
+CDEFS+=-DOJI
+.ENDIF
+
+.IF "$(WITH_MOZILLA)" != "NO"
+
+.IF "$(DISABLE_XAW)" == "TRUE"
+CDEFS+=-DDISABLE_XAW
+.ENDIF
+
+SLOFILES=\
+ $(SLO)$/nppapi.obj \
+ $(SLO)$/sysplug.obj \
+ $(SLO)$/mediator.obj \
+ $(SLO)$/plugcon.obj \
+ $(SLO)$/unxmgr.obj
+
+OBJFILES=\
+ $(OBJ)$/npwrap.obj \
+ $(OBJ)$/npnapi.obj \
+ $(OBJ)$/mediator.obj \
+ $(OBJ)$/plugcon.obj
+
+APP1TARGET=pluginapp.bin
+APP1OBJS=$(OBJFILES)
+APP1STDLIBS=\
+ $(VOSLIB) \
+ $(SALLIB)
+.IF "$(OS)"=="SOLARIS" || "$(OS)"=="SCO" || "$(OS)"=="HPUX"
+APP1STDLIBS+=-lXm -lXt $(X11LINK_DYNAMIC) -ldl
+.ELSE
+.IF "$(DISABLE_XAW)" != "TRUE"
+APP1STDLIBS+=-lXaw
+.ENDIF
+.IF "$(OS)"=="FREEBSD" || "$(OS)"=="NETBSD"
+APP1STDLIBS+= -lXt -lXext -lX11
+.ELSE
+APP1STDLIBS+= -lXt $(X11LINK_DYNAMIC) -ldl
+.ENDIF
+.ENDIF
+
+.IF "$(ENABLE_GTK)" == "TRUE"
+# libs for gtk plugin
+APP1STDLIBS+=$(PKGCONFIG_LIBS:s/ -lpangoxft-1.0//)
+# hack for faked SO environment
+.IF "$(PKGCONFIG_ROOT)"!=""
+.IF "$(OS)" == "SOLARIS"
+# don't ask, it's ugly
+DIRECT :=-z nodefs $(DIRECT)
+.ENDIF
+.ENDIF # "$(PKGCONFIG_ROOT)"!=""
+.ENDIF
+
+
+APP1DEF= $(MISC)$/$(TARGET).def
+
+.ENDIF # $(WITH_MOZILLA) != "NO"
+
+.ENDIF # $(GUIBASE)==aqua
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/extensions/source/plugin/unx/mediator.cxx b/extensions/source/plugin/unx/mediator.cxx
new file mode 100644
index 000000000000..6191fa5e897a
--- /dev/null
+++ b/extensions/source/plugin/unx/mediator.cxx
@@ -0,0 +1,309 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_extensions.hxx"
+#include <errno.h>
+#include <unistd.h>
+
+#include <plugin/unx/mediator.hxx>
+#include <vcl/svapp.hxx>
+
+#define MEDIATOR_MAGIC 0xf7a8d2f4
+
+Mediator::Mediator( int nSocket ) :
+ m_nSocket( nSocket ),
+ m_pListener( NULL ),
+ m_nCurrentID( 1 ),
+ m_bValid( true )
+{
+ m_pListener = new MediatorListener( this );
+ m_pListener->create();
+}
+
+Mediator::~Mediator()
+{
+ if( m_pListener )
+ {
+ {
+ ::vos::OGuard aGuard( m_pListener->m_aMutex );
+ m_pListener->m_pMediator = NULL;
+ }
+ m_pListener = NULL;
+ if( m_bValid )
+ {
+ ULONG aHeader[3];
+ aHeader[0] = 0;
+ aHeader[1] = 0;
+ aHeader[2] = MEDIATOR_MAGIC;
+ write( m_nSocket, aHeader, sizeof( aHeader ) );
+ }
+ // kick the thread out of its run method; it deletes itself
+ close( m_nSocket );
+ }
+ else
+ close( m_nSocket );
+ for( std::vector< MediatorMessage* >::iterator it = m_aMessageQueue.begin();
+ it != m_aMessageQueue.end(); ++it )
+ {
+ delete *it;
+ }
+}
+
+
+ULONG Mediator::SendMessage( ULONG nBytes, const char* pBytes, ULONG nMessageID )
+{
+ if( ! m_pListener )
+ return 0;
+
+ NAMESPACE_VOS(OGuard) aGuard( m_aSendMutex );
+ if( ! nMessageID )
+ nMessageID = m_nCurrentID;
+
+ m_nCurrentID++;
+ if( m_nCurrentID >= 1 << 24 ) // protection against overflow
+ m_nCurrentID = 1;
+
+ if( ! m_bValid )
+ return nMessageID;
+
+ ULONG* pBuffer = new ULONG[ (nBytes/sizeof(ULONG)) + 4 ];
+ pBuffer[ 0 ] = nMessageID;
+ pBuffer[ 1 ] = nBytes;
+ pBuffer[ 2 ] = MEDIATOR_MAGIC;
+ memcpy( &pBuffer[3], pBytes, (size_t)nBytes );
+ write( m_nSocket, pBuffer, nBytes + 3*sizeof( ULONG ) );
+ delete [] pBuffer;
+
+ return nMessageID;
+}
+
+BOOL Mediator::WaitForMessage( ULONG nTimeOut )
+{
+ if( ! m_pListener )
+ return FALSE;
+
+ size_t nItems = m_aMessageQueue.size();
+
+ if( ! nTimeOut && nItems > 0 )
+ return TRUE;
+
+ TimeValue aValue;
+ aValue.Seconds = nTimeOut/1000;
+ aValue.Nanosec = ( nTimeOut % 1000 ) * 1000;
+
+ while( m_aMessageQueue.size() == nItems )
+ {
+ m_aNewMessageCdtn.wait( & aValue );
+ m_aNewMessageCdtn.reset();
+ if( nTimeOut && m_aMessageQueue.size() == nItems )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+MediatorMessage* Mediator::WaitForAnswer( ULONG nMessageID )
+{
+ nMessageID &= 0x00ffffff;
+ while( m_pListener )
+ {
+ {
+ NAMESPACE_VOS(OGuard) aGuard( m_aQueueMutex );
+ for( size_t i = 0; i < m_aMessageQueue.size(); i++ )
+ {
+ MediatorMessage* pMessage = m_aMessageQueue[ i ];
+ ULONG nID = pMessage->m_nID;
+ if( ( nID & 0xff000000 ) &&
+ ( ( nID & 0x00ffffff ) == nMessageID ) )
+ {
+ m_aMessageQueue.erase( m_aMessageQueue.begin() + i );
+ return pMessage;
+ }
+ }
+ }
+ WaitForMessage( 10 );
+ }
+ return NULL;
+}
+
+MediatorMessage* Mediator::GetNextMessage( BOOL bWait )
+{
+ while( m_pListener )
+ {
+ {
+ // guard must be after WaitForMessage, else the listener
+ // cannot insert a new one -> deadlock
+ NAMESPACE_VOS(OGuard) aGuard( m_aQueueMutex );
+ for( size_t i = 0; i < m_aMessageQueue.size(); i++ )
+ {
+ MediatorMessage* pMessage = m_aMessageQueue[ i ];
+ if( ! ( pMessage->m_nID & 0xff000000 ) )
+ {
+ m_aMessageQueue.erase( m_aMessageQueue.begin() + i );
+ return pMessage;
+ }
+ }
+ if( ! bWait )
+ return NULL;
+ }
+ WaitForMessage();
+ }
+ return NULL;
+}
+
+MediatorMessage* Mediator::TransactMessage( ULONG nBytes, char* pBytes )
+{
+ ULONG nID = SendMessage( nBytes, pBytes );
+ return WaitForAnswer( nID );
+}
+
+MediatorListener::MediatorListener( Mediator* pMediator ) :
+ m_pMediator( pMediator )
+{
+}
+
+MediatorListener::~MediatorListener()
+{
+}
+
+void MediatorListener::run()
+{
+ bool bRun = true;
+ while( schedule() && m_pMediator && bRun )
+ {
+ ULONG nHeader[ 3 ];
+ int nBytes;
+
+ if( m_pMediator && ( nBytes = read( m_pMediator->m_nSocket, nHeader, sizeof( nHeader ) ) ) == sizeof( nHeader ) && nHeader[2] == MEDIATOR_MAGIC)
+ {
+ if( nHeader[ 0 ] == 0 && nHeader[ 1 ] == 0 )
+ return;
+ char* pBuffer = new char[ nHeader[ 1 ] ];
+ if( m_pMediator && (ULONG)read( m_pMediator->m_nSocket, pBuffer, nHeader[ 1 ] ) == nHeader[ 1 ] )
+ {
+ ::vos::OGuard aMyGuard( m_aMutex );
+ {
+ NAMESPACE_VOS(OGuard)
+ aGuard( m_pMediator->m_aQueueMutex );
+ MediatorMessage* pMessage =
+ new MediatorMessage( nHeader[ 0 ], nHeader[ 1 ], pBuffer );
+ m_pMediator->m_aMessageQueue.push_back( pMessage );
+ }
+ m_pMediator->m_aNewMessageCdtn.set();
+ m_pMediator->m_aNewMessageHdl.Call( m_pMediator );
+ }
+ else
+ {
+ medDebug( 1, "got incomplete MediatorMessage: { %d, %d, %*s }\n",
+ nHeader[0], nHeader[1], nHeader[1], pBuffer );
+ bRun = false;
+ }
+ delete [] pBuffer;
+ }
+ else
+ {
+ medDebug( 1, "got incomplete message header of %d bytes ( nHeader = [ %u, %u ] ), errno is %d\n",
+ nBytes, nHeader[ 0 ], nHeader[ 1 ], (int)errno );
+ bRun = false;
+ }
+ }
+}
+
+void MediatorListener::onTerminated()
+{
+ if( m_pMediator )
+ {
+ m_pMediator->m_aConnectionLostHdl.Call( m_pMediator );
+ m_pMediator->m_pListener = NULL;
+ }
+ delete this;
+}
+
+ULONG MediatorMessage::ExtractULONG()
+{
+ if( ! m_pRun )
+ m_pRun = m_pBytes;
+
+ medDebug( (ULONG)(m_pRun - m_pBytes) >= m_nBytes, "Overflow in MediatorMessage::ExtractULONG\n" );
+ ULONG nCount;
+ memcpy( &nCount, m_pRun, sizeof( ULONG ) );
+ m_pRun += sizeof( ULONG );
+ return nCount;
+}
+
+void* MediatorMessage::GetBytes( ULONG& rBytes )
+{
+ if( ! m_pRun )
+ m_pRun = m_pBytes;
+
+ medDebug( (ULONG)(m_pRun - m_pBytes) >= m_nBytes, "Overflow in MediatorMessage::GetBytes\n" );
+ ULONG nBytes = ExtractULONG();
+
+ if( nBytes == 0 )
+ return NULL;
+
+ medDebug( (ULONG)(m_pRun - m_pBytes) >= m_nBytes, "Overflow in MediatorMessage::GetBytes\n" );
+ char* pBuffer = new char[ nBytes ];
+ memcpy( pBuffer, m_pRun, nBytes );
+ m_pRun += nBytes;
+ rBytes = nBytes;
+ return pBuffer;
+}
+
+char* MediatorMessage::GetString()
+{
+ if( ! m_pRun )
+ m_pRun = m_pBytes;
+
+ medDebug( (ULONG)(m_pRun - m_pBytes) >= m_nBytes, "Overflow in MediatorMessage::GetString\n" );
+ ULONG nBytes = ExtractULONG();
+
+ if( nBytes == 0 )
+ return NULL;
+
+ medDebug( (ULONG)(m_pRun - m_pBytes) >= m_nBytes, "Overflow in MediatorMessage::GetString\n" );
+ char* pBuffer = new char[ nBytes+1 ];
+ memcpy( pBuffer, m_pRun, nBytes );
+ pBuffer[ nBytes ] = 0;
+ m_pRun += nBytes;
+ return pBuffer;
+}
+
+UINT32 MediatorMessage::GetUINT32()
+{
+ if( ! m_pRun )
+ m_pRun = m_pBytes;
+
+ medDebug( (ULONG)(m_pRun - m_pBytes) >= m_nBytes, "Overflow in MediatorMessage::GetUINT32\n" );
+ ULONG nBytes = ExtractULONG();
+ medDebug( nBytes != sizeof( UINT32 ), "No UINT32 in MediatorMessage::GetUINT32\n" );
+ medDebug( (ULONG)(m_pRun - m_pBytes) >= m_nBytes, "Overflow in MediatorMessage::GetUINT32\n" );
+ UINT32 nRet;
+ memcpy( &nRet, m_pRun, sizeof( nRet ) );
+ m_pRun += sizeof( UINT32 );
+ return nRet;
+}
diff --git a/extensions/source/plugin/unx/npnapi.cxx b/extensions/source/plugin/unx/npnapi.cxx
new file mode 100644
index 000000000000..003b4d0943a5
--- /dev/null
+++ b/extensions/source/plugin/unx/npnapi.cxx
@@ -0,0 +1,898 @@
+/*************************************************************************
+
+ Source Code Control System - Header
+
+ $Header: /zpool/svn/migration/cvs_rep_09_09_08/code/extensions/source/plugin/unx/npnapi.cxx,v 1.11 2008-01-14 14:53:25 ihi Exp $
+
+*************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_extensions.hxx"
+#include <plugin/unx/plugcon.hxx>
+
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <osl/module.h>
+
+extern PluginConnector* pConnector;
+extern XtAppContext app_context;
+extern int wakeup_fd[];
+extern Widget topLevel, topBox;
+extern Display* pAppDisplay;
+extern Display* pXtAppDisplay;
+extern int nAppArguments;
+extern char** pAppArguments;
+
+void* CreateNewShell( void**, XLIB_Window );
+
+// begin Netscape plugin api calls
+extern "C" {
+
+static void* l_NPN_MemAlloc( uint32 nBytes )
+{
+ void* pMem = new char[nBytes];
+ return pMem;
+}
+
+static void l_NPN_MemFree( void* pMem )
+{
+ delete [] (char*)pMem;
+}
+
+static uint32 l_NPN_MemFlush( uint32 /*nSize*/ )
+{
+ return 0;
+}
+
+static NPError l_NPN_DestroyStream( NPP instance, NPStream* stream, NPError reason )
+{
+ UINT32 nInstance = pConnector->GetNPPID( instance );
+ if( nInstance == PluginConnector::UnknownNPPID )
+ return NPERR_GENERIC_ERROR;
+
+ UINT32 nFileID = pConnector->GetStreamID( stream );
+ MediatorMessage* pMes=
+ pConnector->
+ Transact( eNPN_DestroyStream,
+ &nInstance, sizeof( nInstance ),
+ &nFileID, sizeof( nFileID ),
+ POST_STRING( stream->url ),
+ &reason, sizeof( reason ),
+ NULL );
+
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ for( std::vector< NPStream* >::iterator it = pConnector->getStreamList().begin();
+ it != pConnector->getStreamList().end(); ++it )
+ {
+ if( *it == stream )
+ {
+ pConnector->getStreamList().erase( it );
+ break;
+ }
+ }
+ delete [] stream->url;
+ delete stream;
+ // returns NPError
+ NPError aRet = pConnector->GetNPError( pMes );
+ delete pMes;
+ return aRet;
+}
+
+#ifdef OJI
+static JRIEnv* l_NPN_GetJavaEnv()
+{
+ // no java in this program
+ medDebug( 1, "SNI: NPN_GetJavaEnv\n" );
+ return NULL;
+}
+
+static jref l_NPN_GetJavaPeer( NPP /*instance*/ )
+{
+ medDebug( 1, "SNI: NPN_GetJavaPeer\n" );
+ return NULL;
+}
+#endif
+
+static NPError l_NPN_GetURL( NPP instance, const char* url, const char* window )
+{
+ UINT32 nInstance = pConnector->GetNPPID( instance );
+ if( nInstance == PluginConnector::UnknownNPPID )
+ return NPERR_GENERIC_ERROR;
+
+ MediatorMessage* pMes=
+ pConnector->
+ Transact( eNPN_GetURL,
+ &nInstance, sizeof( nInstance ),
+ POST_STRING(url),
+ POST_STRING(window),
+ NULL );
+ medDebug( !pMes, "geturl: message unaswered\n" );
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ // returns NPError
+ NPError aRet = pConnector->GetNPError( pMes );
+ medDebug( aRet, "geturl returns %d\n", (int)aRet );
+ delete pMes;
+ return aRet;
+}
+
+static NPError l_NPN_GetURLNotify( NPP instance, const char* url, const char* target,
+ void* notifyData )
+{
+ UINT32 nInstance = pConnector->GetNPPID( instance );
+ if( nInstance == PluginConnector::UnknownNPPID )
+ return NPERR_GENERIC_ERROR;
+
+ MediatorMessage* pMes=
+ pConnector->
+ Transact( eNPN_GetURLNotify,
+ &nInstance, sizeof( nInstance ),
+ POST_STRING(url),
+ POST_STRING(target),
+ &notifyData, sizeof( void* ), // transmit the actual pointer
+ // since it is a pointer to private data fed back
+ // by NPP_URLNotify; this can be thought of as an ID
+ NULL );
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ // returns NPError
+ NPError aRet = pConnector->GetNPError( pMes );
+ delete pMes;
+ return aRet;
+}
+
+static NPError l_NPN_NewStream( NPP instance, NPMIMEType type, const char* target,
+ NPStream** stream )
+ // stream is a return value
+{
+ UINT32 nInstance = pConnector->GetNPPID( instance );
+ if( nInstance == PluginConnector::UnknownNPPID )
+ return NPERR_GENERIC_ERROR;
+
+ MediatorMessage* pMes=
+ pConnector->
+ Transact( eNPN_NewStream,
+ &nInstance, sizeof( nInstance ),
+ POST_STRING(type),
+ POST_STRING(target),
+ NULL );
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ // returns a new NPStream and an error
+ NPError aRet = pConnector->GetNPError( pMes );
+ if( ! aRet )
+ {
+ NPStream* pStream = new NPStream;
+ pStream->url = pMes->GetString();
+ pStream->end = pMes->GetUINT32();
+ pStream->lastmodified = pMes->GetUINT32();
+ pStream->ndata = pStream->pdata = pStream->notifyData = NULL;
+
+ pConnector->getStreamList().push_back( pStream );
+ *stream = pStream;
+ }
+
+ delete pMes;
+ return aRet;
+}
+
+static NPError l_NPN_PostURLNotify( NPP instance, const char* url, const char* target, uint32 len, const char* buf, NPBool file, void* notifyData )
+{
+ UINT32 nInstance = pConnector->GetNPPID( instance );
+ if( nInstance == PluginConnector::UnknownNPPID )
+ return NPERR_GENERIC_ERROR;
+
+ MediatorMessage* pMes = pConnector->
+ Transact( eNPN_PostURLNotify,
+ &nInstance, sizeof( nInstance ),
+ POST_STRING( url ),
+ POST_STRING( target ),
+ &len, sizeof( len ),
+ buf, len,
+ &file, sizeof( NPBool ),
+ &notifyData, sizeof( void* ), // send the real pointer
+ NULL );
+
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ NPError aRet = pConnector->GetNPError( pMes );
+ delete pMes;
+ return aRet;
+}
+
+static NPError l_NPN_PostURL( NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file )
+{
+ UINT32 nInstance = pConnector->GetNPPID( instance );
+ if( nInstance == PluginConnector::UnknownNPPID )
+ return NPERR_GENERIC_ERROR;
+
+ MediatorMessage* pMes = pConnector->
+ Transact( eNPN_PostURL,
+ &nInstance, sizeof( nInstance ),
+ POST_STRING( url ),
+ POST_STRING( window ),
+ &len, sizeof( len ),
+ buf, len,
+ &file, sizeof( NPBool ),
+ NULL );
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ NPError aRet = pConnector->GetNPError( pMes );
+ delete pMes;
+ return aRet;
+}
+
+static NPError l_NPN_RequestRead( NPStream* stream, NPByteRange* rangeList )
+{
+ medDebug( 1, "pluginapp: NPN_RequestRead\n" );
+
+ NPByteRange* pRange = rangeList;
+ UINT32 nRanges = 0;
+ while( pRange )
+ {
+ nRanges++;
+ pRange = pRange->next;
+ }
+
+ UINT32* pArray = new UINT32[ 2 * nRanges ];
+ pRange = rangeList;
+ UINT32 n = 0;
+ while( pRange )
+ {
+ pArray[ 2*n ] = (UINT32)pRange->offset;
+ pArray[ 2*n + 1] = (UINT32)pRange->length;
+ n++;
+ pRange = pRange->next;
+ }
+ UINT32 nFileID = pConnector->GetStreamID( stream );
+ MediatorMessage* pMes = pConnector->
+ Transact( eNPN_RequestRead,
+ &nFileID, sizeof( nFileID ),
+ &nRanges, sizeof( nRanges ),
+ pArray, sizeof( UINT32 ) * 2 * nRanges,
+ NULL );
+
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ NPError aRet = pConnector->GetNPError( pMes );
+ delete [] pArray;
+ delete pMes;
+ return aRet;
+}
+
+static void l_NPN_Status( NPP instance, const char* message )
+{
+ UINT32 nInstance = pConnector->GetNPPID( instance );
+ if( nInstance == PluginConnector::UnknownNPPID )
+ return;
+
+ pConnector->Send( eNPN_Status,
+ &nInstance, sizeof( nInstance ),
+ POST_STRING( message ),
+ NULL );
+}
+
+static const char* l_NPN_UserAgent( NPP instance )
+{
+ static char* pAgent = NULL;
+
+ UINT32 nInstance = pConnector->GetNPPID( instance );
+ if( nInstance == PluginConnector::UnknownNPPID )
+ {
+ if( instance )
+ return "Mozilla 3.0";
+ else // e.g. flashplayer calls NPN_UserAgent with NULL
+ nInstance = 0;
+ }
+
+ MediatorMessage* pMes = pConnector->
+ Transact( eNPN_UserAgent,
+ &nInstance, sizeof( nInstance ),
+ NULL );
+
+ if( ! pMes )
+ return pAgent;
+
+ if( pAgent )
+ delete [] pAgent;
+ pAgent = pMes->GetString();
+
+ delete pMes;
+
+ medDebug( 1, "NPN_UserAgent returns %s\n", pAgent );
+
+ return pAgent;
+}
+
+#if 0
+static void l_NPN_Version( int* major, int* minor, int* net_major, int* net_minor )
+{
+ MediatorMessage* pMes = pConnector->
+ Transact( eNPN_Version,
+ NULL );
+
+ if( ! pMes )
+ return;
+
+ *major = pMes->GetUINT32();
+ *minor = pMes->GetUINT32();
+ *net_major = pMes->GetUINT32();
+ *net_minor = pMes->GetUINT32();
+
+ medDebug( 1, "pluginapp: NPN_Version: results %d %d, %d %d\n", *major, *minor, *net_major, *net_minor );
+
+ delete pMes;
+}
+#endif
+
+static int32 l_NPN_Write( NPP instance, NPStream* stream, int32 len, void* buffer )
+{
+ UINT32 nFileID = pConnector->GetStreamID( stream );
+ if( nFileID == PluginConnector::UnknownStreamID )
+ return NPERR_GENERIC_ERROR;
+ UINT32 nInstance = pConnector->GetNPPID( instance );
+ if( nInstance == PluginConnector::UnknownNPPID )
+ return NPERR_GENERIC_ERROR;
+
+ MediatorMessage* pMes = pConnector->
+ Transact( eNPN_Write,
+ &nInstance, sizeof( nInstance ),
+ &nFileID, sizeof( nFileID ),
+ &len, sizeof( len ),
+ buffer, len,
+ NULL );
+
+ if( ! pMes )
+ return 0;
+
+ INT32 nRet = pMes->GetUINT32();
+ return nRet;
+}
+
+static void l_NPN_ReloadPlugins( NPBool /*reloadPages*/ )
+{
+ medDebug( 1, "NPN_ReloadPlugins: SNI\n" );
+}
+
+static NPError l_NPN_GetValue( NPP, NPNVariable variable, void* value )
+{
+ /*
+ * We want to handle values injected into a NPNVariable which aren't in
+ * the old enum we build against, but that we know are in the new enum
+ * we want to support
+ */
+ switch( (int)variable )
+ {
+ case NPNVxDisplay:
+ *((Display**)value) = pXtAppDisplay;
+ medDebug( 1, "Display requested\n" );
+ break;
+ case NPNVxtAppContext:
+ *((XtAppContext*)value) = app_context;
+ medDebug( 1, "AppContext requested\n" );
+ break;
+ case NPNVjavascriptEnabledBool:
+ // no javascript
+ *(NPBool*)value = false;
+ medDebug( 1, "javascript enabled requested\n" );
+ break;
+ case NPNVasdEnabledBool:
+ // no SmartUpdate
+ *(NPBool*)value = false;
+ medDebug( 1, "smart update enabled requested\n" );
+ break;
+ case NPNVisOfflineBool:
+ // no offline browsing
+ *(NPBool*)value = false;
+ medDebug( 1, "offline browsing requested\n" );
+ break;
+ case NPNVSupportsXEmbedBool:
+ // asking xembed
+ *(int*)value = true;
+ medDebug( 1, "xembed requested\n" );
+ break;
+ case NPNVToolkit:
+# ifdef ENABLE_GTK
+ *(int*)value = NPNVGtk2;
+# else
+ *(int*)value = 0;
+# endif
+ medDebug( 1, "toolkit requested\n" );
+ break;
+ default:
+ medDebug( 1, "unknown NPNVariable %x requested\n", variable );
+ return NPERR_INVALID_PARAM;
+ }
+ return NPERR_NO_ERROR;
+}
+
+static NPError l_NPN_SetValue(NPP /*instance*/, NPPVariable variable, void *value)
+{
+ medDebug( 1, "NPN_SetValue %d=%p\n", variable, value );
+ return 0;
+}
+
+static void l_NPN_InvalidateRect(NPP /*instance*/, NPRect* /*invalidRect*/)
+{
+ medDebug( 1, "NPN_InvalidateRect\n" );
+}
+
+static void l_NPN_InvalidateRegion(NPP /*instance*/, NPRegion /*invalidRegion*/)
+{
+ medDebug( 1, "NPN_InvalidateRegion\n" );
+}
+
+static void l_NPN_ForceRedraw(NPP /*instance*/)
+{
+ medDebug( 1, "NPN_ForceRedraw\n" );
+}
+
+}
+
+static NPNetscapeFuncs aNetscapeFuncs =
+{
+ sizeof(aNetscapeFuncs),
+ (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR,
+ l_NPN_GetURL,
+ l_NPN_PostURL,
+ l_NPN_RequestRead,
+ l_NPN_NewStream,
+ l_NPN_Write,
+ l_NPN_DestroyStream,
+ l_NPN_Status,
+ l_NPN_UserAgent,
+ l_NPN_MemAlloc,
+ l_NPN_MemFree,
+ l_NPN_MemFlush,
+ l_NPN_ReloadPlugins,
+# ifdef OJI
+ l_NPN_GetJavaEnv,
+ l_NPN_GetJavaPeer,
+# else
+ NULL,
+ NULL,
+# endif
+ l_NPN_GetURLNotify,
+ l_NPN_PostURLNotify,
+ l_NPN_GetValue,
+ l_NPN_SetValue,
+ l_NPN_InvalidateRect,
+ l_NPN_InvalidateRegion,
+ l_NPN_ForceRedraw
+};
+
+static NPPluginFuncs aPluginFuncs =
+{
+ sizeof(aPluginFuncs),
+ (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+oslModule pPluginLib = NULL;
+char*(*pNPP_GetMIMEDescription)() = NULL;
+NPError (*pNP_Initialize)(NPNetscapeFuncs*,NPPluginFuncs*) = NULL;
+NPError (*pNP_Shutdown)() = NULL;
+
+std::vector< PluginConnector* > PluginConnector::allConnectors;
+
+PluginConnector::PluginConnector( int nSocket ) :
+ Mediator( nSocket )
+{
+ SetNewMessageHdl( LINK( this, PluginConnector, NewMessageHdl ) );
+}
+
+PluginConnector::~PluginConnector()
+{
+}
+
+IMPL_LINK( PluginConnector, WorkOnNewMessageHdl, Mediator*, /*pMediator*/ )
+{
+ MediatorMessage* pMessage;
+ CommandAtoms nCommand;
+ while( (pMessage = GetNextMessage( FALSE )) )
+ {
+ nCommand = (CommandAtoms)pMessage->GetUINT32();
+ medDebug( 1, "pluginapp: %s\n", GetCommandName( nCommand ) );
+ switch( nCommand )
+ {
+ case eNPP_DestroyStream:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ UINT32 nFileID = pMessage->GetUINT32();
+ NPStream* pStream = m_aNPWrapStreams[ nFileID ];
+ NPError aReason = GetNPError( pMessage );
+ m_aNPWrapStreams.erase( m_aNPWrapStreams.begin() + nFileID );
+
+ aReason = aPluginFuncs.destroystream( instance, pStream, aReason );
+ Respond( pMessage->m_nID,
+ (char*)&aReason, sizeof( aReason ),
+ NULL );
+
+ delete [] pStream->url;
+ delete pStream;
+ }
+ break;
+ case eNPP_Destroy:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ ConnectorInstance* pInst= m_aInstances[ nInstance ];
+
+ // some plugin rely on old netscapes behaviour
+ // to first destroy the widget and then destroy
+ // the instance, so mimic that behaviour here
+ if( pInst->pShell )
+ XtDestroyWidget( (Widget)pInst->pShell );
+
+ pInst->pWidget = pInst->pShell = NULL;
+
+ // the other side will call eNPP_DestroyPhase2 after this
+ NPError aReason = NPERR_NO_ERROR;
+ Respond( pMessage->m_nID, (char*)&aReason, sizeof( aReason ), NULL );
+ }
+ break;
+ case eNPP_DestroyPhase2:
+ {
+ // now really destroy the instance
+ UINT32 nInstance = pMessage->GetUINT32();
+ ConnectorInstance* pInst= m_aInstances[ nInstance ];
+ NPP instance = pInst->instance;
+ NPSavedData* pSave = NULL;
+
+ NPError aRet = aPluginFuncs.destroy( instance, &pSave );
+ if( pSave )
+ {
+ Respond( pMessage->m_nID,
+ (char*)&aRet, sizeof( aRet ),
+ pSave->buf, pSave->len,
+ NULL );
+ delete [] (char*)pSave->buf;
+ }
+ else
+ Respond( pMessage->m_nID,
+ (char*)&aRet, sizeof( aRet ),
+ "0000", 4,
+ NULL );
+
+ #ifdef ENABLE_GTK
+ if( pInst->pGtkWindow )
+ g_object_unref( G_OBJECT(pInst->pGtkWindow) );
+ if( pInst->pGtkWidget )
+ g_object_unref( G_OBJECT(pInst->pGtkWidget) );
+ #endif
+
+ m_aInstances.erase( m_aInstances.begin() + nInstance );
+ delete pInst;
+ delete instance;
+ medDebug( 1, "destroyed instance (returning %d)\n", aRet );
+ }
+ break;
+ case eNPP_NewStream:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ char* pType = pMessage->GetString();
+ NPStream* pStream = new NPStream;
+ pStream->url = pMessage->GetString();
+ pStream->end = pMessage->GetUINT32();
+ pStream->lastmodified = pMessage->GetUINT32();
+ pStream->pdata = pStream->ndata = pStream->notifyData = NULL;
+ NPBool* pSeekable = (NPBool*)pMessage->GetBytes();
+ m_aNPWrapStreams.push_back( pStream );
+ uint16 nStype = NP_ASFILE;
+ NPError aRet = aPluginFuncs.newstream( instance, pType, pStream,
+ *pSeekable, &nStype );
+ medDebug( 1, "pluginapp: NPP_NewStream( %p, %s, %p, %s, %p ) returns %d\n"
+ "stream = { pdata = %p, ndata = %p, url = %s, end = %d, lastmodified = %d, notifyData = %p }\n",
+ instance, pType, pStream, *pSeekable ? "seekable" : "not seekable", &nStype, (int)aRet,
+ pStream->pdata, pStream->ndata, pStream->url, pStream->end, pStream->lastmodified, pStream->notifyData );
+ Respond( pMessage->m_nID,
+ (char*)&aRet, sizeof( aRet ),
+ &nStype, sizeof( nStype ),
+ NULL );
+ delete [] pType;
+ delete [] pSeekable;
+ }
+ break;
+ case eNPP_New:
+ {
+ char* pType = pMessage->GetString();
+ uint16* pMode = (uint16*)pMessage->GetBytes();
+ int16* pArgc = (int16*)pMessage->GetBytes();
+ NPP instance = new NPP_t;
+ instance->pdata = instance->ndata = NULL;
+ ULONG nArgnBytes, nArgvBytes;
+ char* pArgn = (char*)pMessage->GetBytes( nArgnBytes );
+ char* pArgv = (char*)pMessage->GetBytes( nArgvBytes );
+ ULONG nSaveBytes;
+ char* pSavedData = (char*)pMessage->GetBytes( nSaveBytes );
+ ConnectorInstance* pInst =
+ new ConnectorInstance( instance, pType,
+ *pArgc,
+ pArgn, nArgnBytes,
+ pArgv, nArgvBytes,
+ pSavedData, nSaveBytes );
+ m_aInstances.push_back( pInst );
+ NPError aRet;
+ aRet = aPluginFuncs.newp( pInst->pMimeType, instance, *pMode, *pArgc,
+ pInst->nArg ? pInst->argn : NULL,
+ pInst->nArg ? pInst->argv : NULL,
+ ( nSaveBytes == 4 && *(UINT32*)pSavedData == 0 ) ?
+ &(pInst->aData) : NULL );
+ medDebug( 1, "pluginapp: NPP_New( %s, %p, %d, %d, %p, %p, %p ) returns %d\n",
+ pInst->pMimeType,
+ instance, *pMode, pInst->nArg, pInst->argn, pInst->argv, &pInst->aData,
+ (int) aRet );
+#if OSL_DEBUG_LEVEL > 1
+ for( int i = 0; i < pInst->nArg; i++ )
+ medDebug( 1, " \"%s\"=\"%s\"\n", pInst->argn[i], pInst->argv[i] );
+#endif
+
+ #ifdef ENABLE_GTK
+ // check if XEMBED is to be used
+ // ask for Bool. there seems to be no clear definition whether the
+ // return value should be an int or unsigned char
+ // int can hold both and will be nonzero in case of "true"
+ if( aPluginFuncs.getvalue )
+ {
+ int bNeedsXEmbed = 0;
+ NPError error = aPluginFuncs.getvalue( instance, NPPVpluginNeedsXEmbed, (void *)&bNeedsXEmbed );
+ if( error == NPERR_NO_ERROR )
+ pInst->bShouldUseXEmbed = (bNeedsXEmbed != 0);
+ medDebug( 1, "should use xembed = %s\n", pInst->bShouldUseXEmbed ? "true" : "false" );
+ }
+ #endif
+
+ Respond( pMessage->m_nID,
+ (char*)&aRet, sizeof( aRet ),
+ NULL );
+ delete [] pMode;
+ delete [] pArgc;
+ delete [] pType;
+ }
+ break;
+ case eNPP_SetWindow:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ ConnectorInstance* pInst= m_aInstances[ nInstance ];
+ NPWindow* pWindow = (NPWindow*)pMessage->GetBytes();
+
+ if( pWindow->width < 1 )
+ pWindow->width = 1;
+ if( pWindow->height < 1 )
+ pWindow->height = 1;
+
+ #ifdef ENABLE_GTK
+ if( pInst->bShouldUseXEmbed )
+ {
+ if( ! pInst->pGtkWidget )
+ {
+ medDebug( 1, "creating gtk plug and socket\n" );
+
+ pInst->pGtkWindow = gtk_plug_new((GdkNativeWindow)reinterpret_cast<sal_uIntPtr>(pWindow->window));
+ gtk_widget_show( pInst->pGtkWindow );
+ pInst->pGtkWidget = gtk_socket_new();
+ gtk_widget_show( pInst->pGtkWidget );
+ gtk_container_add( GTK_CONTAINER(pInst->pGtkWindow), pInst->pGtkWidget );
+ gtk_widget_show_all( pInst->pGtkWindow );
+ pInst->window.window = (void *)gtk_socket_get_id( GTK_SOCKET(pInst->pGtkWidget ) );
+
+ XSync( pAppDisplay, False );
+
+ XMapWindow( pAppDisplay, GDK_WINDOW_XWINDOW(pInst->pGtkWindow->window) );
+
+ XSync( pAppDisplay, False );
+ }
+
+ // update widget size; alas out parent is not yet really XEMBED conformant
+ gtk_widget_set_size_request( pInst->pGtkWidget, pWindow->width, pWindow->height );
+ gtk_window_resize( GTK_WINDOW(pInst->pGtkWindow), pWindow->width, pWindow->height );
+
+ GdkScreen* pGdkScreen = gtk_widget_get_screen( pInst->pGtkWidget );
+ Screen* pScreen = ScreenOfDisplay( pAppDisplay, gdk_screen_get_number( pGdkScreen ) );
+
+ pInst->window.x = 0;
+ pInst->window.y = 0;
+ pInst->window.width = pWindow->width;
+ pInst->window.height = pWindow->height;
+ pInst->window.clipRect.left = 0;
+ pInst->window.clipRect.top = 0;
+ pInst->window.clipRect.right = pWindow->width;
+ pInst->window.clipRect.bottom = pWindow->height;
+ pInst->window.ws_info = &pInst->ws_info;
+ pInst->window.type = NPWindowTypeWindow;
+ pInst->ws_info.type = NP_SETWINDOW;
+ pInst->ws_info.display = pAppDisplay;
+ pInst->ws_info.visual = DefaultVisualOfScreen( pScreen );
+ pInst->ws_info.colormap = DefaultColormapOfScreen( pScreen );
+ pInst->ws_info.depth = DefaultDepthOfScreen( pScreen );
+ }
+ else
+ #endif
+ {
+ if( ! pInst->pWidget )
+ {
+ pInst->pWidget = CreateNewShell( &(pInst->pShell), (XLIB_Window)pWindow->window );
+ }
+
+ // fill in NPWindow and NPCallbackStruct
+ pInst->window.window = (void*)XtWindow( (Widget)pInst->pWidget );
+ pInst->window.x = 0;
+ pInst->window.y = 0;
+ pInst->window.width = pWindow->width;
+ pInst->window.height = pWindow->height;
+ pInst->window.clipRect.left = 0;
+ pInst->window.clipRect.top = 0;
+ pInst->window.clipRect.right = pWindow->width;
+ pInst->window.clipRect.bottom = pWindow->height;
+ pInst->window.ws_info = &pInst->ws_info;
+ pInst->window.type = NPWindowTypeWindow;
+ pInst->ws_info.type = NP_SETWINDOW;
+ pInst->ws_info.display = XtDisplay( (Widget)pInst->pWidget );
+ pInst->ws_info.visual = DefaultVisualOfScreen( XtScreen( (Widget)pInst->pWidget ) );
+ pInst->ws_info.colormap = DefaultColormapOfScreen( XtScreen( (Widget)pInst->pWidget ) );
+ pInst->ws_info.depth = DefaultDepthOfScreen( XtScreen( (Widget)pInst->pWidget ) );
+
+ XtResizeWidget( (Widget)pInst->pShell,
+ pInst->window.width,
+ pInst->window.height,
+ 0 );
+ XtResizeWidget( (Widget)pInst->pWidget,
+ pInst->window.width,
+ pInst->window.height,
+ 0 );
+ }
+
+ NPError aRet = aPluginFuncs.setwindow( pInst->instance, &pInst->window );
+ medDebug( 1, "pluginapp: NPP_SetWindow returns %d\n", (int) aRet );
+ Respond( pMessage->m_nID,
+ (char*)&aRet, sizeof( aRet ),
+ NULL );
+ delete [] (char*)pWindow;
+ }
+ break;
+ case eNPP_StreamAsFile:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ UINT32 nFileID = pMessage->GetUINT32();
+ NPStream* pStream = m_aNPWrapStreams[ nFileID ];
+ char* fname = pMessage->GetString();
+ medDebug( 1, "pluginapp: NPP_StreamAsFile %s\n", fname );
+ aPluginFuncs.asfile( instance, pStream, fname );
+ delete [] fname;
+ }
+ break;
+ case eNPP_URLNotify:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ char* url = pMessage->GetString();
+ NPReason* pReason = (NPReason*)pMessage->GetBytes();
+ void** notifyData = (void**)pMessage->GetBytes();
+ aPluginFuncs.urlnotify( instance, url, *pReason, *notifyData );
+ delete [] url;
+ delete [] pReason;
+ delete [] notifyData;
+ }
+ break;
+ case eNPP_WriteReady:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ UINT32 nFileID = pMessage->GetUINT32();
+ NPStream* pStream = m_aNPWrapStreams[ nFileID ];
+ int32 nRet = aPluginFuncs.writeready( instance, pStream );
+
+ medDebug( 1, "pluginapp: NPP_WriteReady( %p, %p ) (stream id = %d) returns %d\n",
+ instance, pStream, nFileID, nRet );
+
+ Respond( pMessage->m_nID,
+ (char*)&nRet, sizeof( nRet ),
+ NULL );
+ }
+ break;
+ case eNPP_Write:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ UINT32 nFileID = pMessage->GetUINT32();
+ NPStream* pStream = m_aNPWrapStreams[ nFileID ];
+ int32 offset = pMessage->GetUINT32();
+ ULONG len;
+ char* buffer = (char*)pMessage->GetBytes( len );
+ int32 nRet = aPluginFuncs.write( instance, pStream, offset, len, buffer );
+
+ medDebug( 1,"pluginapp: NPP_Write( %p, %p, %d, %d, %p ) returns %d\n"
+ "stream = { pdata = %p, ndata = %p, url = %s, end = %d, lastmodified = %d, notifyData = %p }\n",
+ instance, pStream, offset, len, buffer, nRet,
+ pStream->pdata, pStream->ndata, pStream->url, pStream->end, pStream->lastmodified, pStream->notifyData );
+
+ Respond( pMessage->m_nID,
+ (char*)&nRet, sizeof( nRet ),
+ NULL );
+ delete [] buffer;
+ }
+ break;
+ case eNPP_GetMIMEDescription:
+ {
+ if( ! pNPP_GetMIMEDescription )
+ pNPP_GetMIMEDescription = (char*(*)())
+ osl_getAsciiFunctionSymbol( pPluginLib, "NPP_GetMIMEDescription" );
+ char* pMIME = pNPP_GetMIMEDescription();
+ Respond( pMessage->m_nID,
+ POST_STRING( pMIME ),
+ NULL );
+ }
+ break;
+ case eNPP_Initialize:
+ {
+
+ pNP_Initialize =
+ (NPError(*)(NPNetscapeFuncs*, NPPluginFuncs*))
+ osl_getAsciiFunctionSymbol( pPluginLib, "NP_Initialize" );
+ medDebug( !pNP_Initialize, "no NP_Initialize, %s\n", dlerror() );
+ pNP_Shutdown = (NPError(*)())
+ osl_getAsciiFunctionSymbol( pPluginLib, "NP_Shutdown" );
+ medDebug( !pNP_Initialize, "no NP_Shutdown, %s\n", dlerror() );
+
+ medDebug( 1, "entering NP_Initialize\n" );
+ NPError aRet = pNP_Initialize( &aNetscapeFuncs, &aPluginFuncs );
+ medDebug( 1, "pluginapp: NP_Initialize returns %d\n", (int) aRet );
+ Respond( pMessage->m_nID, (char*)&aRet, sizeof( aRet ), NULL );
+ }
+ break;
+ case eNPP_Shutdown:
+ {
+ write( wakeup_fd[1], "xxxx", 4 );
+ }
+ break;
+ default:
+ medDebug( 1, "caught unknown NPP request %d\n", nCommand );
+ break;
+ }
+ delete pMessage;
+ }
+ return 0;
+}
+
+void LoadAdditionalLibs( const char* _pPluginLib )
+{
+ medDebug( 1, "LoadAdditionalLibs %s\n", _pPluginLib );
+
+ if( ! strncmp( _pPluginLib, "libflashplayer.so", 17 ) )
+ {
+ /* #b4951312# flash 7 implicitly assumes a gtk application
+ * if the API version is greater or equal to 12 (probably
+ * because they think they run in mozilla then). In that
+ * case they try to find gtk within the process and crash
+ * when they don't find it.
+ */
+ aNetscapeFuncs.version = 11;
+ aPluginFuncs.version = 11;
+ }
+}
+
diff --git a/extensions/source/plugin/unx/nppapi.cxx b/extensions/source/plugin/unx/nppapi.cxx
new file mode 100644
index 000000000000..6dc1b7a30407
--- /dev/null
+++ b/extensions/source/plugin/unx/nppapi.cxx
@@ -0,0 +1,602 @@
+/*************************************************************************
+
+ Source Code Control System - Header
+
+ $Header: /zpool/svn/migration/cvs_rep_09_09_08/code/extensions/source/plugin/unx/nppapi.cxx,v 1.7 2008-01-14 14:53:38 ihi Exp $
+
+*************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_extensions.hxx"
+
+#if STLPORT_VERSION>=321
+#include <cstdarg>
+#endif
+
+#include <plugin/impl.hxx>
+#include <vcl/svapp.hxx>
+
+std::vector<PluginConnector*> PluginConnector::allConnectors;
+
+PluginConnector::PluginConnector( int nSocket ) :
+ Mediator( nSocket )
+{
+ allConnectors.push_back( this );
+ SetNewMessageHdl( LINK( this, PluginConnector, NewMessageHdl ) );
+}
+
+PluginConnector::~PluginConnector()
+{
+ NAMESPACE_VOS(OGuard) aGuard( m_aUserEventMutex );
+ for( std::vector< PluginConnector* >::iterator it = allConnectors.begin();
+ it != allConnectors.end(); ++it )
+ {
+ if( *it == this )
+ {
+ allConnectors.erase( it );
+ break;
+ }
+ }
+}
+
+IMPL_LINK( PluginConnector, NewMessageHdl, Mediator*, /*pMediator*/ )
+{
+ NAMESPACE_VOS(OGuard) aGuard( m_aUserEventMutex );
+ bool bFound = false;
+ for( std::vector< PluginConnector* >::iterator it = allConnectors.begin();
+ it != allConnectors.end() && bFound == false; ++it )
+ {
+ if( *it == this )
+ bFound = true;
+ }
+ if( ! bFound )
+ return 0;
+ Application::PostUserEvent( LINK( this, PluginConnector, WorkOnNewMessageHdl ) );
+ return 0;
+}
+
+IMPL_LINK( PluginConnector, WorkOnNewMessageHdl, Mediator*, /*pMediator*/ )
+{
+ bool bFound = false;
+ for( std::vector< PluginConnector* >::iterator it = allConnectors.begin();
+ it != allConnectors.end() && bFound == false; ++it )
+ {
+ if( *it == this )
+ bFound = true;
+ }
+ if( ! bFound )
+ return 0;
+/*
+ {
+ NAMESPACE_VOS(OGuard) aGuard( m_aUserEventMutex );
+ m_aUserEventIDs.pop_front();
+ }
+*/
+
+ MediatorMessage* pMessage;
+ CommandAtoms nCommand;
+ while( (pMessage = GetNextMessage( FALSE )) )
+ {
+ nCommand = (CommandAtoms)pMessage->GetUINT32();
+ medDebug( 1, "%s\n", GetCommandName( nCommand ) );
+ switch( nCommand )
+ {
+ case eNPN_GetURL:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ char* pUrl = pMessage->GetString();
+ char* pWindow = pMessage->GetString();
+ NPError aRet = NPN_GetURL( instance, pUrl, pWindow );
+ Respond( pMessage->m_nID,
+ (char*)(&aRet), sizeof( NPError ), NULL );
+ delete [] pUrl;
+ delete [] pWindow;
+ }
+ break;
+ case eNPN_GetURLNotify:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ char* pUrl = pMessage->GetString();
+ char* pWindow = pMessage->GetString();
+ void** pNotifyData = (void**)pMessage->GetBytes();
+ NPError aRet = NPN_GetURLNotify( instance, pUrl, pWindow,
+ *pNotifyData );
+ Respond( pMessage->m_nID,
+ (char*)(&aRet), sizeof( NPError ), NULL );
+ delete [] pUrl;
+ delete [] pWindow;
+ delete [] pNotifyData;
+ }
+ break;
+ case eNPN_DestroyStream:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ UINT32 nFileID = pMessage->GetUINT32();
+ char* pUrl = pMessage->GetString();
+ NPError* pReason = (NPError*)pMessage->GetBytes();
+ NPError aRet = NPERR_FILE_NOT_FOUND;
+ if( nFileID < static_cast<UINT32>(m_aNPWrapStreams.size()) )
+ {
+ if( ! strcmp( m_aNPWrapStreams[ nFileID ]->url, pUrl ) )
+ {
+ aRet =
+ NPN_DestroyStream( instance, m_aNPWrapStreams[ nFileID ],
+ *pReason );
+ m_aNPWrapStreams.erase( m_aNPWrapStreams.begin() + nFileID );
+ }
+ else
+ medDebug( 1, "StreamID %d has incoherent urls %s and %s\n",
+ nFileID, pUrl, m_aNPWrapStreams[ nFileID ]->url );
+ }
+ else
+ medDebug( 1, "Nonexistent StreamID %d\n", nFileID );
+
+ Respond( pMessage->m_nID,
+ (char*)(&aRet), sizeof( NPError ), NULL );
+
+ delete [] pUrl;
+ delete [] pReason;
+ }
+ break;
+ case eNPN_NewStream:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ NPMIMEType pType = pMessage->GetString();
+ char* pTarget = pMessage->GetString();
+
+ NPStream* pStream = NULL;
+
+ NPError aRet = NPN_NewStream( instance, pType, pTarget, &pStream );
+
+ if( aRet != NPERR_NO_ERROR )
+ {
+ UINT32 nDummy = 0;
+ Respond( pMessage->m_nID,
+ (char*)&aRet, sizeof( aRet ),
+ "", 0,
+ &nDummy, sizeof(UINT32),
+ &nDummy, sizeof(UINT32),
+ NULL );
+ }
+ else
+ {
+ m_aNPWrapStreams.push_back( pStream );
+
+ ULONG nLen = strlen( pStream->url );
+ Respond( pMessage->m_nID,
+ (char*)&aRet, sizeof( aRet ),
+ pStream->url, nLen,
+ &pStream->end, sizeof(UINT32),
+ &pStream->lastmodified, sizeof(UINT32),
+ NULL );
+ }
+
+ delete [] pTarget;
+ delete [] pType;
+ }
+ break;
+ case eNPN_PostURLNotify:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ char* pUrl = pMessage->GetString();
+ char* pTarget = pMessage->GetString();
+ UINT32 nLen = pMessage->GetUINT32();
+ char* pBuf = (char*)pMessage->GetBytes();
+ NPBool* pFile = (NPBool*)pMessage->GetBytes();
+ void** pNData = (void**)pMessage->GetBytes();
+ NPError aRet =
+ NPN_PostURLNotify( instance, pUrl, pTarget, nLen, pBuf, *pFile, *pNData );
+ Respond( pMessage->m_nID, (char*)&aRet, sizeof( aRet ), NULL );
+ delete [] pUrl;
+ delete [] pTarget;
+ delete [] pBuf;
+ delete [] pFile;
+ delete [] pNData;
+ }
+ break;
+ case eNPN_PostURL:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ char* pUrl = pMessage->GetString();
+ char* pWindow = pMessage->GetString();
+ UINT32 nLen = pMessage->GetUINT32();
+ char* pBuf = (char*)pMessage->GetBytes();
+ NPBool* pFile = (NPBool*)pMessage->GetBytes();
+ NPError aRet =
+ NPN_PostURL( instance, pUrl, pWindow, nLen, pBuf, *pFile );
+ Respond( pMessage->m_nID, (char*)&aRet, sizeof( aRet ), NULL );
+ delete [] pUrl;
+ delete [] pWindow;
+ delete [] pBuf;
+ delete [] pFile;
+ }
+ break;
+ case eNPN_RequestRead:
+ {
+ UINT32 nFileID = pMessage->GetUINT32();
+ NPStream* pStream = m_aNPWrapStreams[ nFileID ];
+ UINT32 nRanges = pMessage->GetUINT32();
+ UINT32* pArray = (UINT32*)pMessage->GetBytes();
+ // build ranges table
+ NPByteRange* pFirst = new NPByteRange;
+ NPByteRange* pRun = pFirst;
+ for( UINT32 n = 0; n < nRanges; n++ )
+ {
+ pRun->offset = pArray[ 2*n ];
+ pRun->length = pArray[ 2*n+1 ];
+ pRun->next = n < nRanges-1 ? new NPByteRange : NULL;
+ pRun = pRun->next;
+ }
+ NPError aRet = NPN_RequestRead( pStream, pFirst );
+ Respond( pMessage->m_nID, (char*)&aRet, sizeof( aRet ), NULL );
+ while( pFirst )
+ {
+ pRun = pFirst->next;
+ delete pFirst;
+ pFirst = pRun;
+ }
+ delete [] pArray;
+ }
+ break;
+ case eNPN_Status:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ char* pString = pMessage->GetString();
+ NPN_Status( instance, pString );
+ delete [] pString;
+ }
+ break;
+ case eNPN_Version:
+ {
+ int major, minor, net_major, net_minor;
+ NPN_Version( &major, &minor, &net_major, &net_minor );
+ Respond( pMessage->m_nID,
+ (char*)&major, sizeof( int ),
+ &minor, sizeof( int ),
+ &net_major, sizeof( int ),
+ &net_minor, sizeof( int ),
+ NULL );
+ }
+ break;
+ case eNPN_Write:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ UINT32 nFileID = pMessage->GetUINT32();
+ NPStream* pStream = m_aNPWrapStreams[ nFileID ];
+ INT32 nLen = pMessage->GetUINT32();
+ void* pBuffer = pMessage->GetBytes();
+ INT32 nRet = NPN_Write( instance, pStream, nLen, pBuffer );
+ Respond( pMessage->m_nID,
+ (char*)&nRet, sizeof( nRet ),
+ NULL );
+ delete [] (char*)pBuffer;
+ delete instance;
+ }
+ break;
+ case eNPN_UserAgent:
+ {
+ UINT32 nInstance = pMessage->GetUINT32();
+ NPP instance = m_aInstances[ nInstance ]->instance;
+ const char* pAnswer = NPN_UserAgent( instance );
+ Respond( pMessage->m_nID,
+ (char*)pAnswer, strlen( pAnswer ),
+ NULL );
+ }
+ break;
+ default:
+ medDebug( 1, "caught unknown NPN request %d\n", nCommand );
+ }
+
+ delete pMessage;
+ }
+ return 0;
+}
+
+#define GET_INSTANCE() \
+ UINT32 nInstance; \
+ nInstance = GetNPPID( instance );
+
+#define GET_INSTANCE_RET( err ) \
+ GET_INSTANCE() \
+ if( nInstance == PluginConnector::UnknownNPPID ) \
+ return err
+
+
+#define POST_INSTANCE() (char*)&nInstance, sizeof( nInstance )
+
+NPError UnxPluginComm::NPP_Destroy( NPP instance, NPSavedData** save )
+{
+ NPError aRet = NPERR_GENERIC_ERROR;
+ GET_INSTANCE_RET( aRet );
+ MediatorMessage* pMes =
+ Transact( eNPP_Destroy,
+ POST_INSTANCE(),
+ NULL );
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+ delete pMes;
+
+ pMes = Transact( eNPP_DestroyPhase2,
+ POST_INSTANCE(),
+ NULL );
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ aRet = GetNPError( pMes );
+ ULONG nSaveBytes;
+ void* pSaveData = pMes->GetBytes( nSaveBytes );
+ if( nSaveBytes == 4 && *(UINT32*)pSaveData == 0 )
+ *save = NULL;
+ else
+ {
+ *save = new NPSavedData;
+ (*save)->len = nSaveBytes;
+ (*save)->buf = pSaveData;
+ }
+ delete pMes;
+
+ return aRet;
+}
+
+NPError UnxPluginComm::NPP_DestroyStream( NPP instance, NPStream* stream, NPError reason )
+{
+ NPError aRet = NPERR_GENERIC_ERROR;
+ GET_INSTANCE_RET( aRet );
+ UINT32 nFileID = GetStreamID( stream );
+ if( nFileID == PluginConnector::UnknownStreamID )
+ return NPERR_GENERIC_ERROR;
+
+ MediatorMessage* pMes =
+ Transact( eNPP_DestroyStream,
+ POST_INSTANCE(),
+ &nFileID, sizeof( nFileID ),
+ &reason, sizeof( reason ),
+ NULL );
+ m_aNPWrapStreams.erase( m_aNPWrapStreams.begin() + nFileID );
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ aRet = GetNPError( pMes );
+ delete pMes;
+ return aRet;
+}
+
+void* UnxPluginComm::NPP_GetJavaClass()
+{
+ return NULL;
+}
+
+NPError UnxPluginComm::NPP_Initialize()
+{
+ MediatorMessage* pMes =
+ Transact( eNPP_Initialize,
+ NULL );
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ NPError aRet = GetNPError( pMes );
+ delete pMes;
+ return aRet;
+}
+
+NPError UnxPluginComm::NPP_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
+ char* argn[], char* argv[], NPSavedData *saved )
+{
+ m_aInstances.push_back(
+ new ConnectorInstance( instance, pluginType, 0,
+ NULL, 0, NULL, 0,
+ saved ? (char*)saved->buf : NULL,
+ saved ? saved->len : 0 ) );
+
+ char *pArgnBuf, *pArgvBuf;
+ size_t nArgnLen = 0, nArgvLen = 0;
+ int i;
+ for( i = 0; i < argc; i++ )
+ {
+ nArgnLen += strlen( argn[i] ) +1;
+ nArgvLen += strlen( argv[i] ) +1;
+ }
+ pArgnBuf = new char[ nArgnLen ];
+ pArgvBuf = new char[ nArgvLen ];
+ char* pRunArgn = pArgnBuf;
+ char* pRunArgv = pArgvBuf;
+ for( i = 0; i < argc; i++ )
+ {
+ strcpy( pRunArgn, argn[i] );
+ strcpy( pRunArgv, argv[i] );
+ pRunArgn += strlen( argn[i] ) +1;
+ pRunArgv += strlen( argv[i] ) +1;
+ }
+
+ MediatorMessage* pMes;
+ if( saved )
+ pMes =
+ Transact( eNPP_New,
+ pluginType, strlen( pluginType ),
+ &mode, sizeof( mode ),
+ &argc, sizeof( argc ),
+ pArgnBuf, nArgnLen,
+ pArgvBuf, nArgvLen,
+ saved->buf, static_cast<size_t>(saved->len),
+ NULL );
+ else
+ pMes =
+ Transact( eNPP_New,
+ pluginType, strlen( pluginType ),
+ &mode, sizeof( mode ),
+ &argc, sizeof( argc ),
+ pArgnBuf, nArgnLen,
+ pArgvBuf, nArgvLen,
+ "0000", size_t(4),
+ NULL );
+ delete [] pArgnBuf;
+ delete [] pArgvBuf;
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ NPError aRet = GetNPError( pMes );
+ delete pMes;
+
+ return aRet;
+}
+
+NPError UnxPluginComm::NPP_NewStream( NPP instance, NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype )
+{
+ NPError aRet = NPERR_GENERIC_ERROR;
+ GET_INSTANCE_RET( aRet );
+
+ m_aNPWrapStreams.push_back( stream );
+ MediatorMessage* pMes =
+ Transact( eNPP_NewStream,
+ POST_INSTANCE(),
+ type, strlen( type ),
+ stream->url, strlen( stream->url ),
+ &stream->end, sizeof( stream->end ),
+ &stream->lastmodified, sizeof( stream->lastmodified ),
+ &seekable, sizeof( seekable ),
+ NULL );
+
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ aRet = GetNPError( pMes );
+ uint16* pSType = (uint16*)pMes->GetBytes();
+ *stype = *pSType;
+
+ delete [] pSType;
+ delete pMes;
+ return aRet;
+}
+
+void UnxPluginComm::NPP_Print( NPP /*instance*/, NPPrint* /*platformPrint*/ )
+{
+}
+
+NPError UnxPluginComm::NPP_SetWindow( NPP instance, NPWindow* window )
+{
+ NPError aRet = NPERR_GENERIC_ERROR;
+ GET_INSTANCE_RET( aRet );
+
+ MediatorMessage* pMes =
+ Transact( eNPP_SetWindow,
+ POST_INSTANCE(),
+ window, sizeof( NPWindow ),
+ NULL );
+ if( ! pMes )
+ return NPERR_GENERIC_ERROR;
+
+ aRet = GetNPError( pMes );
+ delete pMes;
+ return aRet;
+}
+
+void UnxPluginComm::NPP_Shutdown()
+{
+ Send( eNPP_Shutdown, NULL );
+}
+
+void UnxPluginComm::NPP_StreamAsFile( NPP instance, NPStream* stream, const char* fname )
+{
+ GET_INSTANCE();
+ UINT32 nFileID = GetStreamID( stream );
+ if( nFileID == PluginConnector::UnknownStreamID )
+ return;
+
+ Send( eNPP_StreamAsFile,
+ POST_INSTANCE(),
+ &nFileID, sizeof( nFileID ),
+ fname, strlen( fname ),
+ NULL );
+}
+
+void UnxPluginComm::NPP_URLNotify( NPP instance, const char* url, NPReason reason, void* notifyData )
+{
+ GET_INSTANCE();
+
+ Send( eNPP_URLNotify,
+ POST_INSTANCE(),
+ url, strlen( url ),
+ &reason, sizeof( reason ),
+ &notifyData, sizeof( void* ),
+ NULL );
+}
+
+int32 UnxPluginComm::NPP_Write( NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer )
+{
+ GET_INSTANCE_RET( -1 );
+ UINT32 nFileID = GetStreamID( stream );
+ if( nFileID == PluginConnector::UnknownStreamID )
+ return -1;
+
+ MediatorMessage* pMes =
+ Transact( eNPP_Write,
+ POST_INSTANCE(),
+ &nFileID, sizeof( nFileID ),
+ &offset, sizeof( offset ),
+ buffer, static_cast<size_t>(len),
+ NULL );
+ if( ! pMes )
+ return 0;
+
+ int32 aRet = pMes->GetUINT32();
+ delete pMes;
+
+ return aRet;
+}
+
+int32 UnxPluginComm::NPP_WriteReady( NPP instance, NPStream* stream )
+{
+ GET_INSTANCE_RET( -1 );
+ UINT32 nFileID = GetStreamID( stream );
+ if( nFileID == PluginConnector::UnknownStreamID )
+ return -1;
+
+ MediatorMessage* pMes =
+ Transact( eNPP_WriteReady,
+ POST_INSTANCE(),
+ &nFileID, sizeof( nFileID ),
+ NULL );
+
+ if( ! pMes )
+ return 0;
+
+ int32 aRet = pMes->GetUINT32();
+ delete pMes;
+
+ return aRet;
+}
+
+char* UnxPluginComm::NPP_GetMIMEDescription()
+{
+ static char* pDesc = NULL;
+ MediatorMessage* pMes =
+ Transact( eNPP_GetMIMEDescription,
+ NULL );
+ if( ! pMes )
+ return (char*)"";
+
+ if( pDesc )
+ delete [] pDesc;
+ pDesc = pMes->GetString();
+ delete pMes;
+ return pDesc;
+}
+
+NPError UnxPluginComm::NPP_GetValue( NPP /*instance*/, NPPVariable /*variable*/, void* /*value*/ )
+{
+ return 0;
+}
+
+NPError UnxPluginComm::NPP_SetValue( NPP /*instance*/, NPNVariable /*variable*/, void* /*value*/ )
+{
+ return 0;
+}
diff --git a/extensions/source/plugin/unx/npwrap.cxx b/extensions/source/plugin/unx/npwrap.cxx
new file mode 100644
index 000000000000..1be5f9f42a03
--- /dev/null
+++ b/extensions/source/plugin/unx/npwrap.cxx
@@ -0,0 +1,513 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_extensions.hxx"
+#include <errno.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <plugin/unx/plugcon.hxx>
+
+#include <osl/file.h>
+#include <osl/module.h>
+
+PluginConnector* pConnector = NULL;
+
+int nAppArguments = 0;
+char** pAppArguments = NULL;
+Display* pAppDisplay = NULL;
+Display* pXtAppDisplay = NULL;
+
+extern oslModule pPluginLib;
+extern NPError (*pNP_Shutdown)();
+
+void LoadAdditionalLibs(const char*);
+
+XtAppContext app_context;
+Widget topLevel = NULL, topBox = NULL;
+int wakeup_fd[2] = { 0, 0 };
+static bool bPluginAppQuit = false;
+
+static long GlobalConnectionLostHdl( void* /*pInst*/, void* /*pArg*/ )
+{
+ medDebug( 1, "pluginapp exiting due to connection lost\n" );
+
+ write( wakeup_fd[1], "xxxx", 4 );
+ return 0;
+}
+
+extern "C"
+{
+ static int plugin_x_error_handler( Display*, XErrorEvent* )
+ {
+ return 0;
+ }
+
+ #ifndef ENABLE_GTK
+ static void ThreadEventHandler( XtPointer /*client_data*/, int* /*source*/, XtInputId* id )
+ {
+ char buf[256];
+ // clear pipe
+ int len, nLast = -1;
+
+ while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
+ nLast = len-1;
+ if( ! bPluginAppQuit )
+ {
+ if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
+ pConnector->CallWorkHandler();
+ else
+ {
+ // it seems you can use XtRemoveInput only
+ // safely from within the callback
+ // why is that ?
+ medDebug( 1, "removing wakeup pipe\n" );
+ XtRemoveInput( *id );
+ XtAppSetExitFlag( app_context );
+ bPluginAppQuit = true;
+
+ delete pConnector;
+ pConnector = NULL;
+ }
+ }
+ }
+ #endif
+}
+
+
+IMPL_LINK( PluginConnector, NewMessageHdl, Mediator*, /*pMediator*/ )
+{
+ medDebug( 1, "new message handler\n" );
+ write( wakeup_fd[1], "cccc", 4 );
+ return 0;
+
+}
+
+Widget createSubWidget( char* /*pPluginText*/, Widget shell, XLIB_Window aParentWindow )
+{
+ Widget newWidget = XtVaCreateManagedWidget(
+#if defined USE_MOTIF
+ "drawingArea",
+ xmDrawingAreaWidgetClass,
+#else
+ "",
+# if defined DISABLE_XAW
+ compositeWidgetClass,
+# else
+ labelWidgetClass,
+# endif
+#endif
+ shell,
+ XtNwidth, 200,
+ XtNheight, 200,
+ (char *)NULL );
+ XtRealizeWidget( shell );
+ XtRealizeWidget( newWidget );
+
+ medDebug( 1, "Reparenting new widget %x to %x\n", XtWindow( newWidget ), aParentWindow );
+ XReparentWindow( pXtAppDisplay,
+ XtWindow( shell ),
+ aParentWindow,
+ 0, 0 );
+ XtMapWidget( shell );
+ XtMapWidget( newWidget );
+ XRaiseWindow( pXtAppDisplay, XtWindow( shell ) );
+ XSync( pXtAppDisplay, False );
+
+ return newWidget;
+}
+
+void* CreateNewShell( void** pShellReturn, XLIB_Window aParentWindow )
+{
+ XLIB_String n, c;
+ XtGetApplicationNameAndClass(pXtAppDisplay, &n, &c);
+
+ Widget newShell =
+ XtVaAppCreateShell( "pane", c,
+ topLevelShellWidgetClass,
+ pXtAppDisplay,
+ XtNwidth, 200,
+ XtNheight, 200,
+ XtNoverrideRedirect, True,
+ (char *)NULL );
+ *pShellReturn = newShell;
+
+ char pText[1024];
+ sprintf( pText, "starting plugin %s ...", pAppArguments[2] );
+
+ Widget newWidget = createSubWidget( pText, newShell, aParentWindow );
+
+ return newWidget;
+}
+
+static oslModule LoadModule( const char* pPath )
+{
+ ::rtl::OUString sSystemPath( ::rtl::OUString::createFromAscii( pPath ) );
+ ::rtl::OUString sFileURL;
+ osl_getFileURLFromSystemPath( sSystemPath.pData, &sFileURL.pData );
+
+ oslModule pLib = osl_loadModule( sFileURL.pData, SAL_LOADMODULE_LAZY );
+ if( ! pLib )
+ {
+ medDebug( 1, "could not open %s: %s\n", pPath, dlerror() );
+ }
+ return pLib;
+}
+
+// Unix specific implementation
+static void CheckPlugin( const char* pPath )
+{
+ oslModule pLib = LoadModule( pPath );
+
+ char*(*pNP_GetMIMEDescription)() = (char*(*)())
+ osl_getAsciiFunctionSymbol( pLib, "NP_GetMIMEDescription" );
+ if( pNP_GetMIMEDescription )
+ printf( "%s\n", pNP_GetMIMEDescription() );
+ else
+ medDebug( 1, "could not get symbol NP_GetMIMEDescription %s\n", dlerror() );
+
+ osl_unloadModule( pLib );
+}
+
+#if OSL_DEBUG_LEVEL > 1 && defined LINUX
+#include <execinfo.h>
+#endif
+
+extern "C" {
+
+static void signal_handler( int nSig )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "caught signal %d, exiting\n", nSig );
+#ifdef LINUX
+ void* pStack[64];
+ int nStackLevels = backtrace( pStack, sizeof(pStack)/sizeof(pStack[0]) );
+ backtrace_symbols_fd( pStack, nStackLevels, STDERR_FILENO );
+#endif
+#endif
+ if( pConnector )
+ {
+ // ensure that a read on the other side will wakeup
+ delete pConnector;
+ pConnector = NULL;
+ }
+
+ _exit(nSig);
+}
+
+#ifdef ENABLE_GTK
+
+static gboolean noClosure( gpointer )
+{
+ return TRUE;
+}
+
+// Xt events
+static gboolean prepareXtEvent( GSource*, gint* )
+{
+ int nMask = XtAppPending( app_context );
+ return (nMask & XtIMAll) != 0;
+}
+
+static gboolean checkXtEvent( GSource* )
+{
+ int nMask = XtAppPending( app_context );
+ return (nMask & XtIMAll) != 0;
+}
+
+static gboolean dispatchXtEvent( GSource*, GSourceFunc, gpointer )
+{
+ XtAppProcessEvent( app_context, XtIMAll );
+ return TRUE;
+}
+
+static GSourceFuncs aXtEventFuncs =
+{
+ prepareXtEvent,
+ checkXtEvent,
+ dispatchXtEvent,
+ NULL,
+ noClosure,
+ NULL
+};
+
+static gboolean pollXtTimerCallback(gpointer)
+{
+ for(int i = 0; i < 5; i++)
+ {
+ if( (XtAppPending(app_context) & (XtIMAll & ~XtIMXEvent)) == 0 )
+ break;
+ XtAppProcessEvent(app_context, XtIMAll & ~XtIMXEvent);
+ }
+ return TRUE;
+}
+
+static gboolean prepareWakeupEvent( GSource*, gint* )
+{
+ struct pollfd aPoll = { wakeup_fd[0], POLLIN, 0 };
+ poll( &aPoll, 1, 0 );
+ return (aPoll.revents & POLLIN ) != 0;
+}
+
+static gboolean checkWakeupEvent( GSource* pSource )
+{
+ gint nDum = 0;
+ return prepareWakeupEvent( pSource, &nDum );
+}
+
+static gboolean dispatchWakeupEvent( GSource*, GSourceFunc, gpointer )
+{
+ char buf[256];
+ // clear pipe
+ int len, nLast = -1;
+
+ while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
+ nLast = len-1;
+ if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
+ pConnector->CallWorkHandler();
+ else
+ {
+ XtAppSetExitFlag( app_context );
+ bPluginAppQuit = true;
+
+ delete pConnector;
+ pConnector = NULL;
+ }
+
+ return TRUE;
+}
+
+static GSourceFuncs aWakeupEventFuncs = {
+ prepareWakeupEvent,
+ checkWakeupEvent,
+ dispatchWakeupEvent,
+ NULL,
+ noClosure,
+ NULL
+};
+
+#endif // GTK
+
+}
+
+int main( int argc, char **argv)
+{
+ struct sigaction aSigAction;
+ aSigAction.sa_handler = signal_handler;
+ sigemptyset( &aSigAction.sa_mask );
+ aSigAction.sa_flags = SA_NOCLDSTOP;
+ sigaction( SIGSEGV, &aSigAction, NULL );
+ sigaction( SIGBUS, &aSigAction, NULL );
+ sigaction( SIGABRT, &aSigAction, NULL );
+ sigaction( SIGTERM, &aSigAction, NULL );
+ sigaction( SIGILL, &aSigAction, NULL );
+
+ int nArg = (argc < 3) ? 1 : 2;
+ char* pBaseName = argv[nArg] + strlen(argv[nArg]);
+ while( pBaseName > argv[nArg] && pBaseName[-1] != '/' )
+ pBaseName--;
+ LoadAdditionalLibs( pBaseName );
+
+ if( argc == 2 )
+ {
+ CheckPlugin(argv[1]);
+ exit(0);
+ }
+ nAppArguments = argc;
+ pAppArguments = argv;
+
+ XSetErrorHandler( plugin_x_error_handler );
+
+ if( pipe( wakeup_fd ) )
+ {
+ medDebug( 1, "could not pipe()\n" );
+ return 1;
+ }
+ // initialize 'wakeup' pipe.
+ int flags;
+
+ // set close-on-exec descriptor flag.
+ if ((flags = fcntl (wakeup_fd[0], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (wakeup_fd[0], F_SETFD, flags);
+ }
+ if ((flags = fcntl (wakeup_fd[1], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (wakeup_fd[1], F_SETFD, flags);
+ }
+
+ // set non-blocking I/O flag.
+ if ((flags = fcntl (wakeup_fd[0], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (wakeup_fd[0], F_SETFL, flags);
+ }
+ if ((flags = fcntl (wakeup_fd[1], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (wakeup_fd[1], F_SETFL, flags);
+ }
+
+ pPluginLib = LoadModule( argv[2] );
+ if( ! pPluginLib )
+ {
+ exit(255);
+ }
+ int nSocket = atol( argv[1] );
+
+ #ifdef ENABLE_GTK
+ g_thread_init(NULL);
+ gtk_init(&argc, &argv);
+ #endif
+
+ pConnector = new PluginConnector( nSocket );
+ pConnector->SetConnectionLostHdl( Link( NULL, GlobalConnectionLostHdl ) );
+
+ XtSetLanguageProc( NULL, NULL, NULL );
+
+ XtToolkitInitialize();
+ app_context = XtCreateApplicationContext();
+ pXtAppDisplay = XtOpenDisplay( app_context, NULL, "SOPlugin", "SOPlugin", NULL, 0, &argc, argv );
+
+
+ #ifdef ENABLE_GTK
+ // integrate Xt events into GTK event loop
+ GPollFD aXtPollDesc, aWakeupPollDesc;
+
+ GSource* pXTSource = g_source_new( &aXtEventFuncs, sizeof(GSource) );
+ if( !pXTSource )
+ {
+ medDebug( 1, "could not get Xt GSource" );
+ return 1;
+ }
+
+ g_source_set_priority( pXTSource, GDK_PRIORITY_EVENTS );
+ g_source_set_can_recurse( pXTSource, TRUE );
+ g_source_attach( pXTSource, NULL );
+ aXtPollDesc.fd = ConnectionNumber( pXtAppDisplay );
+ aXtPollDesc.events = G_IO_IN;
+ aXtPollDesc.revents = 0;
+ g_source_add_poll( pXTSource, &aXtPollDesc );
+
+ gint xt_polling_timer_id = g_timeout_add( 25, pollXtTimerCallback, NULL);
+ // Initialize wakeup events listener
+ GSource *pWakeupSource = g_source_new( &aWakeupEventFuncs, sizeof(GSource) );
+ if ( pWakeupSource == NULL )
+ {
+ medDebug( 1, "could not get wakeup source" );
+ return 1;
+ }
+ g_source_set_priority( pWakeupSource, GDK_PRIORITY_EVENTS);
+ g_source_attach( pWakeupSource, NULL );
+ aWakeupPollDesc.fd = wakeup_fd[0];
+ aWakeupPollDesc.events = G_IO_IN;
+ aWakeupPollDesc.revents = 0;
+ g_source_add_poll( pWakeupSource, &aWakeupPollDesc );
+
+ pAppDisplay = gdk_x11_display_get_xdisplay( gdk_display_get_default() );
+ #else
+ pAppDisplay = pXtAppDisplay;
+ XtAppAddInput( app_context,
+ wakeup_fd[0],
+ (XtPointer)XtInputReadMask,
+ ThreadEventHandler, NULL );
+ #endif
+
+ // send that we are ready to go
+ MediatorMessage* pMessage =
+ pConnector->Transact( "init req", 8,
+ NULL );
+ delete pMessage;
+
+#if OSL_DEBUG_LEVEL > 3
+ int nPID = getpid();
+ int nChild = fork();
+ if( nChild == 0 )
+ {
+ char pidbuf[16];
+ char* pArgs[] = { "xterm", "-sl", "2000", "-sb", "-e", "gdb", "pluginapp.bin", pidbuf, NULL };
+ sprintf( pidbuf, "%d", nPID );
+ execvp( pArgs[0], pArgs );
+ _exit(255);
+ }
+ else
+ sleep( 10 );
+#endif
+
+ /*
+ * Loop for events.
+ */
+ // for some reason XtAppSetExitFlag won't quit the application
+ // in ThreadEventHandler most of times; Xt will hang in select
+ // (hat is in XtAppNextEvent). Have our own mainloop instead
+ // of XtAppMainLoop
+ do
+ {
+ #ifdef ENABLE_GTK
+ g_main_context_iteration( NULL, TRUE );
+ #else
+ XtAppProcessEvent( app_context, XtIMAll );
+ #endif
+ } while( ! XtAppGetExitFlag( app_context ) && ! bPluginAppQuit );
+
+ medDebug( 1, "left plugin app main loop\n" );
+
+ g_source_remove(xt_polling_timer_id);
+
+ pNP_Shutdown();
+ medDebug( 1, "NP_Shutdown done\n" );
+ osl_unloadModule( pPluginLib );
+ medDebug( 1, "plugin close\n" );
+
+ close( wakeup_fd[0] );
+ close( wakeup_fd[1] );
+
+ return 0;
+}
+
+#ifdef GCC
+extern "C" {
+ void __pure_virtual()
+ {}
+
+ void* __builtin_new( int nBytes )
+ { return malloc(nBytes); }
+ void* __builtin_vec_new( int nBytes )
+ { return malloc(nBytes); }
+ void __builtin_delete( char* pMem )
+ { free(pMem); }
+ void __builtin_vec_delete( char* pMem )
+ { free(pMem); }
+}
+#endif
+
diff --git a/extensions/source/plugin/unx/plugcon.cxx b/extensions/source/plugin/unx/plugcon.cxx
new file mode 100644
index 000000000000..74d8fa8bd2da
--- /dev/null
+++ b/extensions/source/plugin/unx/plugcon.cxx
@@ -0,0 +1,282 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_extensions.hxx"
+#include <plugin/unx/plugcon.hxx>
+
+#include <cstdarg>
+#include <vector>
+
+UINT32 PluginConnector::GetStreamID( NPStream* pStream )
+{
+ size_t nLen = m_aNPWrapStreams.size();
+ for( size_t i = 0; i < nLen; i++ )
+ if( m_aNPWrapStreams[ i ] == pStream )
+ return static_cast<UINT32>(i);
+ medDebug( 1, "Error: NPStream has no ID\n" );
+ return UnknownStreamID;
+}
+
+UINT32 PluginConnector::GetNPPID( NPP instance )
+{
+ size_t nLen = m_aInstances.size();
+ for( size_t i=0; i <nLen; i++ )
+ if( m_aInstances[ i ]->instance == instance )
+ return static_cast<UINT32>(i);
+ medDebug( 1, "Error: NPP has no ID\n" );
+
+ return UnknownNPPID;
+}
+
+ConnectorInstance* PluginConnector::getInstance( NPP instance )
+{
+ size_t nLen = m_aInstances.size();
+ for( size_t i=0; i <nLen; i++ )
+ {
+ ConnectorInstance* pInst = m_aInstances[i];
+ if( pInst->instance == instance )
+ return pInst;
+ }
+ return NULL;
+}
+
+ConnectorInstance* PluginConnector::getInstanceById( UINT32 nInstanceID )
+{
+ return nInstanceID < static_cast<UINT32>(m_aInstances.size()) ? m_aInstances[ nInstanceID ] : NULL;
+}
+
+struct PtrStruct
+{
+ char* pData;
+ ULONG nBytes;
+
+ PtrStruct( char* i_pData, ULONG i_nBytes )
+ : pData( i_pData ), nBytes( i_nBytes ) {}
+};
+
+ULONG PluginConnector::FillBuffer( char*& rpBuffer,
+ const char* pFunction,
+ ULONG nFunctionLen,
+ va_list ap )
+{
+ std::vector< PtrStruct > aList;
+ aList.reserve( 5 );
+
+ ULONG nDataSize = nFunctionLen + sizeof( ULONG );
+ char* pNext;
+
+ do {
+ pNext = va_arg( ap, char* );
+ if( pNext )
+ {
+ aList.push_back( PtrStruct( pNext, va_arg( ap, ULONG ) ) );
+ nDataSize += aList.back().nBytes + sizeof(ULONG);
+ }
+ } while( pNext );
+
+ rpBuffer = new char[ nDataSize ];
+ char* pRun = rpBuffer;
+ memcpy( pRun, &nFunctionLen, sizeof( nFunctionLen ) );
+ pRun += sizeof( nFunctionLen );
+ memcpy( pRun, pFunction, nFunctionLen );
+ pRun += nFunctionLen;
+
+ for( std::vector<PtrStruct>::const_iterator it = aList.begin(); it != aList.end(); ++it )
+ {
+ memcpy( pRun, &it->nBytes, sizeof( ULONG ) );
+ pRun += sizeof( ULONG );
+ memcpy( pRun, it->pData, it->nBytes );
+ pRun += it->nBytes;
+ }
+ return nDataSize;
+}
+
+MediatorMessage* PluginConnector::Transact( const char* pFunction,
+ ULONG nFunctionLen, ... )
+{
+ va_list ap;
+ char* pBuffer;
+
+ va_start( ap, nFunctionLen );
+ ULONG nSize = FillBuffer( pBuffer, pFunction, nFunctionLen, ap );
+ va_end( ap );
+ return TransactMessage( nSize, pBuffer );
+}
+
+MediatorMessage* PluginConnector::Transact( UINT32 nFunction, ... )
+{
+ va_list ap;
+ char* pBuffer;
+
+ va_start( ap, nFunction );
+ ULONG nSize = FillBuffer( pBuffer, (char*)&nFunction, sizeof( nFunction ), ap );
+ va_end( ap );
+ return TransactMessage( nSize, pBuffer );
+}
+
+ULONG PluginConnector::Send( UINT32 nFunction, ... )
+{
+ va_list ap;
+ char* pBuffer;
+
+ va_start( ap, nFunction );
+ ULONG nSize = FillBuffer( pBuffer, (char*)&nFunction, sizeof( nFunction ), ap );
+ va_end( ap );
+ return SendMessage( nSize, pBuffer );
+}
+
+void PluginConnector::Respond( ULONG nID,
+ char* pFunction,
+ ULONG nFunctionLen, ... )
+{
+ va_list ap;
+ char* pBuffer;
+
+ va_start( ap, nFunctionLen );
+ ULONG nSize = FillBuffer( pBuffer, pFunction, nFunctionLen, ap );
+ va_end( ap );
+ SendMessage( nSize, pBuffer, nID | ( 1 << 24 ) );
+}
+
+MediatorMessage* PluginConnector::WaitForAnswer( ULONG nMessageID )
+{
+ if( ! m_bValid )
+ return NULL;
+
+ nMessageID &= 0x00ffffff;
+ while( m_pListener )
+ {
+ {
+ NAMESPACE_VOS(OGuard) aGuard( m_aQueueMutex );
+ for( size_t i = 0; i < m_aMessageQueue.size(); i++ )
+ {
+ MediatorMessage* pMessage = m_aMessageQueue[ i ];
+ ULONG nID = pMessage->m_nID;
+ if( ( nID & 0xff000000 ) &&
+ ( ( nID & 0x00ffffff ) == nMessageID ) )
+ {
+ m_aMessageQueue.erase( m_aMessageQueue.begin() + i );
+ return pMessage;
+ }
+ }
+ }
+ if( ! m_aMessageQueue.empty() )
+ CallWorkHandler();
+ WaitForMessage( 2000 );
+ }
+ return NULL;
+}
+
+ConnectorInstance::ConnectorInstance( NPP inst, char* type,
+ int args, char* pargnbuf, ULONG nargnbytes,
+ char* pargvbuf, ULONG nargvbytes,
+ char* savedata, ULONG savebytes ) :
+ instance( inst ),
+ pShell( NULL ),
+ pWidget( NULL ),
+ pForm( NULL ),
+ pGtkWindow( NULL ),
+ pGtkWidget( NULL ),
+ bShouldUseXEmbed( false ),
+ nArg( args ),
+ pArgnBuf( pargnbuf ),
+ pArgvBuf( pargvbuf )
+{
+ memset( &window, 0, sizeof(window) );
+ pMimeType = new char[ strlen( type ) + 1 ];
+ strcpy( pMimeType, type );
+ aData.len = savebytes;
+ aData.buf = savedata;
+ argn = new char*[ nArg ];
+ argv = new char*[ nArg ];
+ int i;
+ char* pRun = pArgnBuf;
+ for( i = 0; i < nArg; i++ )
+ {
+ argn[i] = pRun;
+ while( *pRun != 0 && (ULONG)(pRun - pArgnBuf) < nargnbytes )
+ pRun++;
+ if( (ULONG)(pRun - pArgnBuf) < nargnbytes )
+ pRun++;
+ }
+ pRun = pArgvBuf;
+ for( i = 0; i < nArg; i++ )
+ {
+ argv[i] = pRun;
+ while( *pRun != 0 && (ULONG)(pRun - pArgvBuf) < nargvbytes )
+ pRun++;
+ if( (ULONG)(pRun - pArgvBuf) < nargvbytes )
+ pRun++;
+ }
+}
+
+ConnectorInstance::~ConnectorInstance()
+{
+ delete [] pMimeType;
+ delete [] argn;
+ delete [] argv;
+ delete [] pArgnBuf;
+ delete [] pArgvBuf;
+ delete [] (char*)aData.buf;
+}
+
+const char* GetCommandName( CommandAtoms eCommand )
+{
+ switch( eCommand )
+ {
+ case eNPN_GetURL: return "NPN_GetURL";
+ case eNPN_GetURLNotify: return "NPN_GetURLNotify";
+ case eNPN_DestroyStream: return "NPN_DestroyStream";
+ case eNPN_NewStream: return "NPN_NewStream";
+ case eNPN_PostURLNotify: return "NPN_PostURLNotify";
+ case eNPN_PostURL: return "NPN_PostURL";
+ case eNPN_RequestRead: return "NPN_RequestRead";
+ case eNPN_Status: return "NPN_Status";
+ case eNPN_Version: return "NPN_Version";
+ case eNPN_Write: return "NPN_Write";
+ case eNPN_UserAgent: return "NPN_UserAgent";
+
+ case eNPP_DestroyStream: return "NPP_DestroyStream";
+ case eNPP_Destroy: return "NPP_Destroy";
+ case eNPP_DestroyPhase2: return "NPP_DestroyPhase2";
+ case eNPP_NewStream: return "NPP_NewStream";
+ case eNPP_New: return "NPP_New";
+ case eNPP_SetWindow: return "NPP_SetWindow";
+ case eNPP_StreamAsFile: return "NPP_StreamAsFile";
+ case eNPP_URLNotify: return "NPP_URLNotify";
+ case eNPP_WriteReady: return "NPP_WriteReady";
+ case eNPP_Write: return "NPP_Write";
+ case eNPP_GetMIMEDescription: return "NPP_GetMIMEDescription";
+ case eNPP_Initialize: return "NPP_Initialize";
+ case eNPP_Shutdown: return "NPP_Shutdown";
+
+ case eMaxCommand: return "eMaxCommand";
+ default: return "unknown command";
+ }
+ return NULL;
+}
diff --git a/extensions/source/plugin/unx/sysplug.cxx b/extensions/source/plugin/unx/sysplug.cxx
new file mode 100644
index 000000000000..fbcf9b7497eb
--- /dev/null
+++ b/extensions/source/plugin/unx/sysplug.cxx
@@ -0,0 +1,131 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_extensions.hxx"
+#include <cstdarg>
+
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <osl/file.hxx>
+#include <osl/thread.h>
+#include <rtl/bootstrap.hxx>
+
+#include <plugin/impl.hxx>
+
+int UnxPluginComm::nConnCounter = 0;
+
+UnxPluginComm::UnxPluginComm(
+ const String& /*mimetype*/,
+ const String& library,
+ XLIB_Window aParent,
+ int nDescriptor1,
+ int nDescriptor2
+ ) :
+ PluginComm( ::rtl::OUStringToOString( library, osl_getThreadTextEncoding() ), false ),
+ PluginConnector( nDescriptor2 )
+{
+ char pDesc[32];
+ char pWindow[32];
+ sprintf( pWindow, "%d", (int)aParent );
+ sprintf( pDesc, "%d", nDescriptor1 );
+ ByteString aLib( library, osl_getThreadTextEncoding() );
+ rtl::OString path;
+ if (!getPluginappPath(&path)) {
+ fprintf( stderr, "cannot construct path to pluginapp.bin\n" );
+ m_nCommPID = -1;
+ return;
+ }
+
+ char const* pArgs[5];
+ pArgs[0] = path.getStr();
+ pArgs[1] = pDesc;
+ pArgs[2] = aLib.GetBuffer();
+ pArgs[3] = pWindow;
+ pArgs[4] = NULL;
+
+#if OSL_DEBUG_LEVEL > 1
+ m_nCommPID = 10;
+ fprintf( stderr, "Try to launch: %s %s %s %s, descriptors are %d, %d\n", pArgs[0], pArgs[1], pArgs[2], pArgs[3], nDescriptor1, nDescriptor2 );
+#endif
+
+ if( ! ( m_nCommPID = fork() ) )
+ {
+ execvp( pArgs[0], const_cast< char ** >(pArgs) );
+ fprintf( stderr, "Error: could not exec %s\n", pArgs[0] );
+ _exit(255);
+ }
+
+ if( m_nCommPID != -1 )
+ {
+ // wait for pluginapp.bin to start up
+ if( ! WaitForMessage( 5000 ) )
+ {
+ fprintf( stderr, "Timeout on command: %s %s %s %s\n", pArgs[0], pArgs[1], pArgs[2], pArgs[3] );
+ invalidate();
+ }
+ else
+ {
+ MediatorMessage* pMessage = GetNextMessage( TRUE );
+ Respond( pMessage->m_nID,
+ const_cast<char*>("init ack"),8,
+ NULL );
+ delete pMessage;
+ NPP_Initialize();
+ }
+ }
+}
+
+UnxPluginComm::~UnxPluginComm()
+{
+ NPP_Shutdown();
+ if( m_nCommPID != -1 && m_nCommPID != 0 )
+ {
+ int status = 16777216;
+ pid_t nExit = waitpid( m_nCommPID, &status, WUNTRACED );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "child %d (plugin app child %d) exited with status %d\n", nExit, m_nCommPID, WEXITSTATUS(status) );
+#else
+ (void)nExit;
+#endif
+ }
+}
+
+bool UnxPluginComm::getPluginappPath(rtl::OString * path) {
+ OSL_ASSERT(path != NULL);
+ rtl::OUString p(
+ RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/program/pluginapp.bin"));
+ rtl::Bootstrap::expandMacros(p);
+ return
+ (osl::FileBase::getSystemPathFromFileURL(p, p) ==
+ osl::FileBase::E_None) &&
+ p.convertToString(
+ path, osl_getThreadTextEncoding(),
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR));
+}
diff --git a/extensions/source/plugin/unx/unxmgr.cxx b/extensions/source/plugin/unx/unxmgr.cxx
new file mode 100644
index 000000000000..1a3736e87e0b
--- /dev/null
+++ b/extensions/source/plugin/unx/unxmgr.cxx
@@ -0,0 +1,315 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_extensions.hxx"
+#include <cstdarg>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <osl/thread.h>
+#include <rtl/strbuf.hxx>
+#include <tools/appendunixshellword.hxx>
+
+#include <vcl/svapp.hxx>
+#include <plugin/impl.hxx>
+
+using namespace rtl;
+using namespace std;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::plugin;
+
+// Unix specific implementation
+static bool CheckPlugin( const ByteString& rPath, list< PluginDescription* >& rDescriptions )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Trying plugin %s ... ", rPath.GetBuffer() );
+#endif
+
+ xub_StrLen nPos = rPath.SearchBackward( '/' );
+ if( nPos == STRING_NOTFOUND )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "no absolute path to plugin\n" );
+#endif
+ return false;
+ }
+
+ ByteString aBaseName = rPath.Copy( nPos+1 );
+ if( aBaseName.Equals( "libnullplugin.so" ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "don't like %s\n", aBaseName.GetBuffer() );
+#endif
+ return false;
+ }
+
+ struct stat aStat;
+ if( stat( rPath.GetBuffer(), &aStat ) || ! S_ISREG( aStat.st_mode ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s is not a regular file\n", rPath.GetBuffer() );
+#endif
+ return false;
+ }
+
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+
+ rtl::OString path;
+ if (!UnxPluginComm::getPluginappPath(&path)) {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cannot construct path to pluginapp.bin\n" );
+#endif
+ return false;
+ }
+ rtl::OStringBuffer cmd;
+ tools::appendUnixShellWord(&cmd, path);
+ cmd.append(' ');
+ tools::appendUnixShellWord(&cmd, rPath);
+ rtl::OString aCommand(cmd.makeStringAndClear());
+
+ FILE* pResult = popen( aCommand.getStr(), "r" );
+ int nDescriptions = 0;
+ if( pResult )
+ {
+ OStringBuffer aMIME;
+ char buf[256];
+ while( fgets( buf, sizeof( buf ), pResult ) )
+ {
+ for( size_t i = 0; i < sizeof(buf) && buf[i]; ++i )
+ {
+ if( buf[i] == '\n' )
+ buf[i] = ';';
+ }
+ aMIME.append( buf );
+ }
+ pclose( pResult );
+
+ if( aMIME.getLength() > 0 )
+ {
+ OString aLine = aMIME.makeStringAndClear();
+
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OString aType = aLine.getToken( 0, ';', nIndex );
+
+ sal_Int32 nTypeIndex = 0;
+ OString aMimetype = aType.getToken( 0, ':', nTypeIndex );
+ OString aExtLine = aType.getToken( 0, ':', nTypeIndex );
+ if( nTypeIndex < 0 ) // ensure at least three tokens
+ continue;
+ OString aDesc = aType.getToken( 0, ':', nTypeIndex );
+
+ // create extension list string
+ sal_Int32 nExtIndex = 0;
+ OStringBuffer aExtension;
+ while( nExtIndex != -1 )
+ {
+ OString aExt = aExtLine.getToken( 0, ',', nExtIndex);
+ if( aExt.indexOf( "*." ) != 0 )
+ aExtension.append( "*." );
+ aExtension.append( aExt );
+ if( nExtIndex != -1 )
+ aExtension.append( ';' );
+ }
+
+ PluginDescription* pNew = new PluginDescription;
+ // set plugin name (path to library)
+ pNew->PluginName = OStringToOUString( rPath, aEncoding );
+ // set mimetype
+ pNew->Mimetype = OStringToOUString( aMimetype, aEncoding );
+ // set extension line
+ pNew->Extension = OStringToOUString( aExtension.makeStringAndClear(), aEncoding );
+ // set description
+ pNew->Description= OStringToOUString( aDesc, aEncoding );
+ rDescriptions.push_back( pNew );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Mimetype: %s\nExtension: %s\n"
+ "Description: %s\n",
+ OUStringToOString( pNew->Mimetype, aEncoding ).getStr(),
+ OUStringToOString( pNew->Extension, aEncoding ).getStr(),
+ OUStringToOString( pNew->Description, aEncoding ).getStr()
+ );
+#endif
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "result of \"%s\" contains no mimtype\n",
+ aCommand.getStr() );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "command \"%s\" failed\n", aCommand.getStr() );
+#endif
+ return nDescriptions > 0;
+}
+
+union maxDirent
+{
+ char aBuffer[ sizeof( struct dirent ) + _PC_NAME_MAX +1 ];
+ struct dirent asDirent;
+};
+
+static void CheckPluginRegistryFiles( const rtl::OString& rPath, list< PluginDescription* >& rDescriptions )
+{
+ rtl::OStringBuffer aPath( 1024 );
+ aPath.append( rPath );
+ aPath.append( "/pluginreg.dat" );
+ FILE* fp = fopen( aPath.getStr(), "r" );
+ if( fp )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "parsing %s\n", aPath.getStr() );
+#endif
+ char aLine[1024];
+ while( fgets( aLine, sizeof( aLine ), fp ) )
+ {
+ int nLineLen = strlen( aLine );
+ int nDotPos;
+ for( nDotPos = nLineLen-1; nDotPos > 0 && aLine[nDotPos] != ':'; nDotPos-- )
+ ;
+ if( aLine[0] == '/' && aLine[nDotPos] == ':' && aLine[nDotPos+1] == '$' )
+ CheckPlugin( ByteString( aLine, nDotPos ), rDescriptions );
+ }
+ fclose( fp );
+ }
+
+ // check subdirectories
+ DIR* pDIR = opendir( rPath.getStr() );
+ struct dirent* pDirEnt = NULL;
+ struct stat aStat;
+ maxDirent u;
+ while( pDIR && ! readdir_r( pDIR, &u.asDirent, &pDirEnt ) && pDirEnt )
+ {
+ char* pBaseName = u.asDirent.d_name;
+ if( rtl_str_compare( ".", pBaseName ) && rtl_str_compare( "..", pBaseName ) )
+ {
+ rtl::OStringBuffer aBuf( 1024 );
+ aBuf.append( rPath );
+ aBuf.append( '/' );
+ aBuf.append( pBaseName );
+
+ if( ! stat( aBuf.getStr(), &aStat ) )
+ {
+ if( S_ISDIR( aStat.st_mode ) )
+ CheckPluginRegistryFiles( aBuf.makeStringAndClear(), rDescriptions );
+ }
+ }
+ }
+ if( pDIR )
+ closedir( pDIR );
+}
+
+Sequence<PluginDescription> XPluginManager_Impl::impl_getPluginDescriptions() throw()
+{
+ static Sequence<PluginDescription> aDescriptions;
+ static BOOL bHavePlugins = FALSE;
+ if( ! bHavePlugins )
+ {
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ list<PluginDescription*> aPlugins;
+ int i;
+
+ // unix: search for plugins in /usr/lib/netscape/plugins,
+ // ~/.netscape/plugins und NPX_PLUGIN_PATH
+ // additionally: search in PluginsPath
+ static const char* pHome = getenv( "HOME" );
+ static const char* pNPXPluginPath = getenv( "NPX_PLUGIN_PATH" );
+
+ ByteString aSearchPath( "/usr/lib/netscape/plugins" );
+ if( pHome )
+ {
+ aSearchPath.Append( ':' );
+ aSearchPath.Append( pHome );
+ aSearchPath += "/.netscape/plugins";
+ }
+ if( pNPXPluginPath )
+ {
+ aSearchPath.Append( ':' );
+ aSearchPath += pNPXPluginPath;
+ }
+
+ const Sequence< ::rtl::OUString >& rPaths( PluginManager::getAdditionalSearchPaths() );
+ for( i = 0; i < rPaths.getLength(); i++ )
+ {
+ aSearchPath += ":";
+ aSearchPath += ByteString( String( rPaths.getConstArray()[i] ), aEncoding );
+ }
+
+ int nPaths = aSearchPath.GetTokenCount( ':' );
+ maxDirent u;
+ for( i = 0; i < nPaths; i++ )
+ {
+ ByteString aPath( aSearchPath.GetToken( i, ':' ) );
+ if( aPath.Len() )
+ {
+ DIR* pDIR = opendir( aPath.GetBuffer() );
+ struct dirent* pDirEnt = NULL;
+ while( pDIR && ! readdir_r( pDIR, &u.asDirent, &pDirEnt ) && pDirEnt )
+ {
+ char* pBaseName = u.asDirent.d_name;
+ if( pBaseName[0] != '.' ||
+ pBaseName[1] != '.' ||
+ pBaseName[2] != 0 )
+ {
+ ByteString aFileName( aPath );
+ aFileName += "/";
+ aFileName += pBaseName;
+ CheckPlugin( aFileName, aPlugins );
+ }
+ }
+ if( pDIR )
+ closedir( pDIR );
+ }
+ }
+
+ // try ~/.mozilla/pluginreg.dat
+ rtl::OStringBuffer aBuf(256);
+ aBuf.append( pHome );
+ aBuf.append( "/.mozilla" );
+ CheckPluginRegistryFiles( aBuf.makeStringAndClear(), aPlugins );
+
+ // create return value
+ aDescriptions = Sequence<PluginDescription>( aPlugins.size() );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %d plugins\n", aPlugins.size() );
+#endif
+ list<PluginDescription*>::iterator iter;
+ for( iter = aPlugins.begin(), i=0; iter != aPlugins.end(); ++iter ,i++ )
+ {
+ aDescriptions.getArray()[ i ] = **iter;
+ delete *iter;
+ }
+ aPlugins.clear();
+ bHavePlugins = TRUE;
+ }
+ return aDescriptions;
+}