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