Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #ifdef UNIX
30 : : #include <sys/stat.h>
31 : : #include <sys/socket.h>
32 : : #include <sys/types.h>
33 : : #include <arpa/inet.h>
34 : : #include <netinet/in.h>
35 : : #endif //end of UNIX
36 : :
37 : : #ifdef WNT
38 : : #ifdef _MSC_VER
39 : : #pragma once
40 : : #pragma warning (push,1)
41 : : #pragma warning (disable:4668)
42 : : #endif
43 : : #define WIN32_LEAN_AND_MEAN
44 : : #include <windows.h>
45 : : #include <winsock2.h>
46 : : #include <malloc.h>
47 : : #include <memory.h>
48 : : #include <tchar.h>
49 : : #ifdef _MSC_VER
50 : : #pragma warning (pop)
51 : : #endif
52 : : #endif //end of WNT
53 : :
54 : : #include <unistd.h>
55 : : #include <stdio.h>
56 : : #include <stdlib.h>
57 : : #include <errno.h>
58 : : #include "boost/scoped_array.hpp"
59 : :
60 : : #include "ns_debug.hxx"
61 : : #include "so_msg.hxx"
62 : : #include "so_instance.hxx"
63 : : #include "so_env.hxx"
64 : :
65 : : #include "nsp_func.hxx"
66 : :
67 : : #include "sal/main.h"
68 : : #include <sal/macros.h>
69 : :
70 : : #include "rtl/process.h"
71 : : #include "rtl/bootstrap.hxx"
72 : : #include "rtl/string.hxx"
73 : : #include "rtl/ustrbuf.hxx"
74 : :
75 : : #include "osl/security.hxx"
76 : : #include "osl/thread.hxx"
77 : :
78 : : #include "cppuhelper/bootstrap.hxx"
79 : :
80 : :
81 : :
82 : : #include "com/sun/star/uno/XComponentContext.hpp"
83 : : #include "com/sun/star/lang/XMultiServiceFactory.hpp"
84 : : #include "com/sun/star/bridge/UnoUrlResolver.hpp"
85 : : #include "com/sun/star/bridge/XUnoUrlResolver.hpp"
86 : :
87 : : #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
88 : :
89 : : using namespace ::rtl;
90 : : using namespace ::osl;
91 : : using namespace ::cppu;
92 : : using namespace ::com::sun::star;
93 : : using namespace ::com::sun::star::uno;
94 : :
95 : :
96 : : #define MAX_NODE_NUM 1024
97 : :
98 : : SoPluginInstance* lpInstance[MAX_NODE_NUM];
99 : :
100 : : static NSP_PIPE_FD la_read_fd = 0;
101 : : static char const * progdir = NULL;
102 : :
103 : :
104 : 0 : long int NSP_ReadFromPipe(NSP_PIPE_FD fp, void* buf, unsigned long int len)
105 : : {
106 : 0 : unsigned long int len_unix = 0, len_wnt = 0;
107 : :
108 : 0 : len_unix = NSP_Read_Pipe(fp, buf, len, &len_wnt);
109 : : #ifdef UNIX
110 : : (void)len_wnt;
111 : 0 : return len_unix;
112 : : #endif //end of UNIX
113 : : #ifdef WNT
114 : : (void)len_unix;
115 : : return len_wnt;
116 : : #endif //end of WNT
117 : :
118 : : }
119 : :
120 : 0 : int find_free_node()
121 : : {
122 : 0 : for(int i=0; i<MAX_NODE_NUM; i++)
123 : : {
124 : 0 : if(NULL == lpInstance[i])
125 : 0 : return i;
126 : : }
127 : 0 : return -1;
128 : : }
129 : :
130 : 0 : int find_cur_node(long cur_id)
131 : : {
132 : 0 : for(int i=0; i<MAX_NODE_NUM; i++)
133 : : {
134 : 0 : if(lpInstance[i] == NULL)
135 : 0 : continue;
136 : 0 : if(cur_id == lpInstance[i]->GetParent())
137 : 0 : return i;
138 : : }
139 : 0 : return -1;
140 : : }
141 : :
142 : 0 : sal_Bool dump_plugin_message(PLUGIN_MSG* pMsg)
143 : : {
144 : 0 : if (!pMsg)
145 : 0 : return sal_False;
146 : : debug_fprintf(NSP_LOG_APPEND, "NSPlugin Message: msg_id:%d; instance_id:%d;wnd_id:%d;wnd_x:%d;wnd_y:%d;wnd_w:%d;wnd_h:%d; url:%s\n",
147 : : pMsg->msg_id, pMsg->instance_id, pMsg->wnd_id,
148 : 0 : pMsg->wnd_x, pMsg->wnd_y, pMsg->wnd_w, pMsg->wnd_h, pMsg->url);
149 : 0 : return sal_True;
150 : : }
151 : :
152 : 0 : int Set_Window(PLUGIN_MSG* pMsg)
153 : : {
154 : 0 : dump_plugin_message(pMsg);
155 : : int cur_no;
156 : 0 : if( -1 == (cur_no = find_cur_node(pMsg->instance_id)))
157 : 0 : return -1;
158 : 0 : if(lpInstance[cur_no]->SetWindow(pMsg->wnd_id,
159 : 0 : pMsg->wnd_x, pMsg->wnd_y, pMsg->wnd_w, pMsg->wnd_h))
160 : 0 : return 0;
161 : : else
162 : 0 : return -1;
163 : : }
164 : :
165 : 0 : int Set_URL(PLUGIN_MSG* pMsg)
166 : : {
167 : 0 : dump_plugin_message(pMsg);
168 : : int cur_no;
169 : 0 : if( -1 == (cur_no = find_cur_node(pMsg->instance_id)))
170 : 0 : return -1;
171 : 0 : if(lpInstance[cur_no]->SetURL(pMsg->url))
172 : 0 : return 0;
173 : : else
174 : 0 : return -1;
175 : : }
176 : :
177 : 0 : int New_Instance(PLUGIN_MSG* pMsg, Reference< lang::XMultiServiceFactory > xMSF)
178 : : {
179 : 0 : dump_plugin_message(pMsg);
180 : : int free_no;
181 : 0 : if( -1 == (free_no = find_free_node()))
182 : 0 : return -1;
183 : 0 : lpInstance[free_no] = new SoPluginInstance(pMsg->instance_id, xMSF);
184 : 0 : return 0;
185 : : }
186 : :
187 : 0 : int Destroy(PLUGIN_MSG* pMsg)
188 : : {
189 : 0 : dump_plugin_message(pMsg);
190 : : int cur_no;
191 : 0 : if( -1 == (cur_no = find_cur_node(pMsg->instance_id)))
192 : 0 : return -1;
193 : 0 : if(lpInstance[cur_no] != NULL)
194 : : {
195 : 0 : lpInstance[cur_no]->Destroy();
196 : 0 : debug_fprintf(NSP_LOG_APPEND, "print by Nsplugin, begin delete.\n");
197 : 0 : delete(lpInstance[cur_no]);
198 : 0 : lpInstance[cur_no] = NULL;
199 : : }
200 : 0 : return 0;
201 : : }
202 : :
203 : 0 : int Print(PLUGIN_MSG* pMsg)
204 : : {
205 : 0 : dump_plugin_message(pMsg);
206 : : int cur_no;
207 : 0 : if( -1 == (cur_no = find_cur_node(pMsg->instance_id)))
208 : 0 : return -1;
209 : 0 : if(lpInstance[cur_no] != NULL)
210 : : {
211 : 0 : lpInstance[cur_no]->Print();
212 : : }
213 : 0 : return 0;
214 : : }
215 : :
216 : 0 : int Shutdown()
217 : : {
218 : 0 : for(int cur_no=0; cur_no<MAX_NODE_NUM; cur_no++)
219 : : {
220 : 0 : if(lpInstance[cur_no] == NULL)
221 : 0 : continue;
222 : 0 : lpInstance[cur_no]->Destroy();
223 : 0 : debug_fprintf(NSP_LOG_APPEND, "print by Nsplugin, begin delete.\n");
224 : 0 : delete(lpInstance[cur_no]);
225 : 0 : lpInstance[cur_no] = NULL;
226 : : }
227 : 0 : return -1;
228 : : }
229 : :
230 : 0 : int dispatchMsg(PLUGIN_MSG* pMsg, Reference< lang::XMultiServiceFactory > xMSF)
231 : : {
232 : 0 : switch(pMsg->msg_id)
233 : : {
234 : : case SO_SET_WINDOW:
235 : 0 : return Set_Window(pMsg);
236 : : case SO_NEW_INSTANCE:
237 : 0 : if(xMSF.is())
238 : 0 : return New_Instance(pMsg, xMSF);
239 : : case SO_SET_URL:
240 : 0 : return Set_URL(pMsg);
241 : : case SO_DESTROY:
242 : 0 : return Destroy(pMsg);
243 : : case SO_SHUTDOWN:
244 : 0 : Shutdown();
245 : 0 : return -1;
246 : : case SO_PRINT:
247 : 0 : Print(pMsg);
248 : 0 : return 0;
249 : : default:
250 : 0 : return -1;
251 : : }
252 : : }
253 : :
254 : 0 : Reference< lang::XMultiServiceFactory > SAL_CALL start_office(NSP_PIPE_FD read_fd)
255 : : {
256 : 0 : Reference< XComponentContext > xRemoteContext;
257 : :
258 : : try
259 : : {
260 : 0 : OUString aOfficePath;
261 : :
262 : : #ifdef UNIX
263 : : boost::scoped_array< char > exepath(
264 : 0 : new char[( progdir ? strlen( progdir ) : 0 ) + RTL_CONSTASCII_LENGTH( "/soffice" ) + 1] );
265 : 0 : if ( progdir )
266 : 0 : sprintf( exepath.get(), "%s/soffice", progdir );
267 : : else
268 : 0 : sprintf( exepath.get(), "soffice" );
269 : 0 : if (!rtl_convertStringToUString(
270 : 0 : &aOfficePath.pData, exepath.get(), strlen(exepath.get()), osl_getThreadTextEncoding(),
271 : : (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
272 : : RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
273 : 0 : RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
274 : : {
275 : 0 : debug_fprintf(NSP_LOG_APPEND,"bad characters in soffice installation path!\n");
276 : 0 : return Reference< lang::XMultiServiceFactory >(NULL);
277 : : }
278 : : #endif //end of UNIX
279 : : #ifdef WNT
280 : : char sPath[NPP_PATH_MAX];
281 : : sPath[0] = 0;
282 : :
283 : : // The quotes will be added in osl_executeProcess
284 : : sprintf(sPath, "%s", findSofficeExecutable() );
285 : : if (!rtl_convertStringToUString(
286 : : &aOfficePath.pData, sPath, strlen(sPath), osl_getThreadTextEncoding(),
287 : : (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
288 : : RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
289 : : RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
290 : : {
291 : : debug_fprintf(NSP_LOG_APPEND,"bad characters in soffice installation path!\n");
292 : : return Reference< lang::XMultiServiceFactory >(NULL);
293 : : }
294 : : #endif //end of WNT
295 : :
296 : : // create default local component context
297 : : Reference< XComponentContext > xLocalContext(
298 : 0 : defaultBootstrap_InitialComponentContext() );
299 : 0 : if ( !xLocalContext.is() )
300 : : {
301 : 0 : debug_fprintf(NSP_LOG_APPEND,"no local component context!\n");
302 : 0 : return Reference< lang::XMultiServiceFactory >(NULL);
303 : : }
304 : :
305 : : // env string
306 : 0 : ::rtl::OUStringBuffer buf;
307 : 0 : OUString aPath, aPluginPipeName;
308 : :
309 : 0 : if(!Bootstrap::get(OUSTR("BRAND_BASE_DIR"), aPath))
310 : : {
311 : 0 : debug_fprintf(NSP_LOG_APPEND,"failed to get BRAND_BASE_DIR!\n");
312 : 0 : return Reference< lang::XMultiServiceFactory >(NULL);
313 : : }
314 : :
315 : 0 : aPluginPipeName = ::rtl::OUString::valueOf( aPath.hashCode() );
316 : :
317 : : // accept string
318 : : OSL_ASSERT( buf.getLength() == 0 );
319 : 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "--accept=pipe,name=" ) );
320 : 0 : buf.append( aPluginPipeName ); //user installation path as pipe name
321 : 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ";urp;" ) );
322 : 0 : OUString sConnectStartString( buf.makeStringAndClear() );
323 : :
324 : : // arguments
325 : : OUString args [] = {
326 : : OUSTR( "--nologo" ),
327 : : OUSTR( "--nodefault" ),
328 : : OUSTR( "--nolockcheck" ),
329 : : sConnectStartString,
330 : 0 : };
331 : :
332 : : // create a URL resolver
333 : : Reference< bridge::XUnoUrlResolver > xUrlResolver(
334 : 0 : bridge::UnoUrlResolver::create( xLocalContext ) );
335 : :
336 : : // connection string
337 : : OSL_ASSERT( buf.getLength() == 0 );
338 : 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "uno:pipe,name=" ) );
339 : 0 : buf.append( aPluginPipeName );
340 : : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
341 : 0 : ";urp;StarOffice.ComponentContext" ) );
342 : 0 : OUString sConnectString( buf.makeStringAndClear() );
343 : :
344 : : try
345 : : {
346 : : // try to connect to office, no need to start instance again if office already started
347 : : xRemoteContext.set(
348 : 0 : xUrlResolver->resolve( sConnectString ), UNO_QUERY_THROW );
349 : 0 : debug_fprintf(NSP_LOG_APPEND, "Staroffice already start\n");
350 : 0 : return Reference< lang::XMultiServiceFactory >(xRemoteContext->getServiceManager(), UNO_QUERY);
351 : : }
352 : 0 : catch ( const connection::NoConnectException & )
353 : : {
354 : : }
355 : :
356 : : // start office process
357 : : #ifdef UNIX
358 : : // a temporary solution
359 : : // in future the process should be started using the osl_executeProcess call
360 : 0 : int nChildPID = fork();
361 : 0 : if( ! nChildPID ) // child process
362 : : {
363 : 0 : NSP_Close_Pipe(read_fd);
364 : : execl( "/bin/sh",
365 : : "/bin/sh",
366 : 0 : ::rtl::OUStringToOString( aOfficePath, osl_getThreadTextEncoding() ).getStr(),
367 : 0 : ::rtl::OUStringToOString( args[0], osl_getThreadTextEncoding() ).getStr(),
368 : 0 : ::rtl::OUStringToOString( args[1], osl_getThreadTextEncoding() ).getStr(),
369 : 0 : ::rtl::OUStringToOString( args[2], osl_getThreadTextEncoding() ).getStr(),
370 : 0 : ::rtl::OUStringToOString( args[3], osl_getThreadTextEncoding() ).getStr(),
371 : 0 : NULL);
372 : 0 : _exit(255);
373 : : }
374 : : #else
375 : : (void) read_fd; /* avoid warning about unused parameter */
376 : : Security sec;
377 : : oslProcess hProcess = 0;
378 : : rtl_uString * ar_args [] = {
379 : : args[ 0 ].pData,
380 : : args[ 1 ].pData,
381 : : args[ 2 ].pData,
382 : : args[ 3 ].pData,
383 : : };
384 : :
385 : : oslProcessError rc = osl_executeProcess(
386 : : aOfficePath.pData,
387 : : ar_args,
388 : : SAL_N_ELEMENTS( ar_args ),
389 : : osl_Process_DETACHED,
390 : : sec.getHandle(),
391 : : 0, // => current working dir
392 : : 0,
393 : : 0, // => no env vars
394 : : &hProcess );
395 : : switch ( rc )
396 : : {
397 : : case osl_Process_E_None:
398 : : osl_freeProcessHandle( hProcess );
399 : : break;
400 : : default:
401 : : debug_fprintf(NSP_LOG_APPEND, "unmapped error!\n");
402 : : return Reference< lang::XMultiServiceFactory >(NULL);
403 : : }
404 : : #endif
405 : :
406 : : // wait until office is started
407 : 0 : for ( int i = 0; i < 240 /* stop the connection after 240 * 500ms */; ++i )
408 : : {
409 : : try
410 : : {
411 : : // try to connect to office
412 : : xRemoteContext.set(
413 : 0 : xUrlResolver->resolve( sConnectString ), UNO_QUERY_THROW );
414 : 0 : return Reference< lang::XMultiServiceFactory >(xRemoteContext->getServiceManager(), UNO_QUERY);
415 : : }
416 : 0 : catch ( const connection::NoConnectException & )
417 : : {
418 : : // wait 500 ms, then try to connect again
419 : 0 : TimeValue tv = { 0 /* secs */, 500000000 /* nanosecs */ };
420 : 0 : ::osl::Thread::wait( tv );
421 : : }
422 : : }
423 : 0 : debug_fprintf(NSP_LOG_APPEND, "Failed to connect to Staroffice in 2 minutes\n");
424 : 0 : return Reference< lang::XMultiServiceFactory >(NULL);
425 : : }
426 : 0 : catch (const Exception & e)
427 : : {
428 : 0 : debug_fprintf(NSP_LOG_APPEND, "unexpected UNO exception caught: ");
429 : 0 : debug_fprintf(NSP_LOG_APPEND, (sal_Char *)e.Message.getStr());
430 : 0 : return Reference< lang::XMultiServiceFactory >(NULL);
431 : 0 : }
432 : :
433 : : }
434 : :
435 : :
436 : 0 : SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
437 : : {
438 : : // Sleep(20*1000);
439 : 0 : debug_fprintf(NSP_LOG_APPEND, "start of main\n");
440 : 0 : memset(lpInstance, 0, sizeof(lpInstance));
441 : :
442 : : // MessageBox( NULL, "nsplugin has been started", "Info", MB_OK );
443 : :
444 : : NSP_PIPE_FD fd_pipe[2];
445 : : int iPipe[2];
446 : 0 : if(argc < 3)
447 : : {
448 : 0 : debug_fprintf(NSP_LOG_APPEND, "print by nsplugin, command error; too little argument to start plugin exec\n");
449 : 0 : return EXIT_FAILURE;
450 : : }
451 : 0 : iPipe[0] = atoi(argv[1]);
452 : 0 : iPipe[1] = atoi(argv[2]);
453 : :
454 : : // fd_pipe[0]: read, fd_pipe[0]: write
455 : 0 : fd_pipe[0] = (NSP_PIPE_FD) iPipe[0] ;
456 : 0 : fd_pipe[1] = (NSP_PIPE_FD) iPipe[1] ;
457 : 0 : NSP_Close_Pipe(fd_pipe[1]);
458 : :
459 : 0 : if(iPipe[0] < 0)
460 : : {
461 : 0 : debug_fprintf(NSP_LOG_APPEND, "print by nsplugin, command error: bad read file id:%s \n", iPipe[0]);
462 : 0 : return 0;
463 : : }
464 : 0 : la_read_fd = fd_pipe[0];
465 : :
466 : : // the program path is provided only on unix, on windows the registry entry is used
467 : 0 : if ( argc > 4 )
468 : 0 : progdir = argv[4];
469 : :
470 : 0 : Reference< lang::XMultiServiceFactory > xFactory = start_office(la_read_fd);
471 : 0 : if(!xFactory.is())
472 : : {
473 : 0 : NSP_Close_Pipe(la_read_fd);
474 : 0 : return -1;
475 : : }
476 : : PLUGIN_MSG nMsg;
477 : : int len;
478 : 0 : while(1)
479 : : {
480 : 0 : memset(&nMsg, 0, sizeof(PLUGIN_MSG));
481 : 0 : len = NSP_ReadFromPipe(la_read_fd, (char*)&nMsg, sizeof(PLUGIN_MSG));
482 : 0 : if(len != sizeof(PLUGIN_MSG))
483 : 0 : break;
484 : 0 : debug_fprintf(NSP_LOG_APPEND, "Read message from pipe type %d \n", nMsg.msg_id);
485 : 0 : if(-1 == dispatchMsg(&nMsg, xFactory))
486 : : {
487 : 0 : debug_fprintf(NSP_LOG_APPEND, "plugin will shutdown\n");
488 : 0 : break;
489 : : }
490 : : }
491 : 0 : NSP_Close_Pipe(la_read_fd);
492 : 0 : _exit(0);
493 : : #ifndef _MSC_VER
494 : 0 : return EXIT_SUCCESS; // avoid warnings
495 : : #endif
496 : : }
497 : :
498 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|