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::number( aPath.hashCode() );
313 :
314 : // accept string
315 : OSL_ASSERT( buf.isEmpty() );
316 0 : buf.append( "--accept=pipe,name=" );
317 0 : buf.append( aPluginPipeName ); //user installation path as pipe name
318 0 : buf.append( ";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.append( "uno:pipe,name=" );
336 0 : buf.append( aPluginPipeName );
337 0 : buf.append( ";urp;StarOffice.ComponentContext" );
338 0 : OUString sConnectString( buf.makeStringAndClear() );
339 :
340 : try
341 : {
342 : // try to connect to office, no need to start instance again if office already started
343 : xRemoteContext.set(
344 0 : xUrlResolver->resolve( sConnectString ), UNO_QUERY_THROW );
345 0 : debug_fprintf(NSP_LOG_APPEND, "Staroffice already start\n");
346 0 : return Reference< lang::XMultiServiceFactory >(xRemoteContext->getServiceManager(), UNO_QUERY);
347 : }
348 0 : catch ( const connection::NoConnectException & )
349 : {
350 : }
351 :
352 : // start office process
353 : #ifdef UNIX
354 : // a temporary solution
355 : // in future the process should be started using the osl_executeProcess call
356 0 : int nChildPID = fork();
357 0 : if( ! nChildPID ) // child process
358 : {
359 0 : NSP_Close_Pipe(read_fd);
360 : execl( "/bin/sh",
361 : "/bin/sh",
362 0 : OUStringToOString( aOfficePath, osl_getThreadTextEncoding() ).getStr(),
363 0 : OUStringToOString( args[0], osl_getThreadTextEncoding() ).getStr(),
364 0 : OUStringToOString( args[1], osl_getThreadTextEncoding() ).getStr(),
365 0 : OUStringToOString( args[2], osl_getThreadTextEncoding() ).getStr(),
366 0 : OUStringToOString( args[3], osl_getThreadTextEncoding() ).getStr(),
367 0 : NULL);
368 0 : _exit(255);
369 : }
370 : #else
371 : (void) read_fd; /* avoid warning about unused parameter */
372 : Security sec;
373 : oslProcess hProcess = 0;
374 : rtl_uString * ar_args [] = {
375 : args[ 0 ].pData,
376 : args[ 1 ].pData,
377 : args[ 2 ].pData,
378 : args[ 3 ].pData,
379 : };
380 :
381 : oslProcessError rc = osl_executeProcess(
382 : aOfficePath.pData,
383 : ar_args,
384 : SAL_N_ELEMENTS( ar_args ),
385 : osl_Process_DETACHED,
386 : sec.getHandle(),
387 : 0, // => current working dir
388 : 0,
389 : 0, // => no env vars
390 : &hProcess );
391 : switch ( rc )
392 : {
393 : case osl_Process_E_None:
394 : osl_freeProcessHandle( hProcess );
395 : break;
396 : default:
397 : debug_fprintf(NSP_LOG_APPEND, "unmapped error!\n");
398 : return Reference< lang::XMultiServiceFactory >(NULL);
399 : }
400 : #endif
401 :
402 : // wait until office is started
403 0 : for ( int i = 0; i < 240 /* stop the connection after 240 * 500ms */; ++i )
404 : {
405 : try
406 : {
407 : // try to connect to office
408 : xRemoteContext.set(
409 0 : xUrlResolver->resolve( sConnectString ), UNO_QUERY_THROW );
410 0 : return Reference< lang::XMultiServiceFactory >(xRemoteContext->getServiceManager(), UNO_QUERY);
411 : }
412 0 : catch ( const connection::NoConnectException & )
413 : {
414 : // wait 500 ms, then try to connect again
415 0 : TimeValue tv = { 0 /* secs */, 500000000 /* nanosecs */ };
416 0 : ::osl::Thread::wait( tv );
417 : }
418 : }
419 0 : debug_fprintf(NSP_LOG_APPEND, "Failed to connect to Staroffice in 2 minutes\n");
420 0 : return Reference< lang::XMultiServiceFactory >(NULL);
421 : }
422 0 : catch (const Exception & e)
423 : {
424 0 : debug_fprintf(NSP_LOG_APPEND, "unexpected UNO exception caught: ");
425 0 : debug_fprintf(NSP_LOG_APPEND, (sal_Char *)e.Message.getStr());
426 0 : return Reference< lang::XMultiServiceFactory >(NULL);
427 0 : }
428 :
429 : }
430 :
431 :
432 0 : SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
433 : {
434 : // Sleep(20*1000);
435 0 : debug_fprintf(NSP_LOG_APPEND, "start of main\n");
436 0 : memset(lpInstance, 0, sizeof(lpInstance));
437 :
438 : // MessageBox( NULL, "nsplugin has been started", "Info", MB_OK );
439 :
440 : NSP_PIPE_FD fd_pipe[2];
441 : int iPipe[2];
442 0 : if(argc < 3)
443 : {
444 0 : debug_fprintf(NSP_LOG_APPEND, "print by nsplugin, command error; too little argument to start plugin exec\n");
445 0 : return EXIT_FAILURE;
446 : }
447 0 : iPipe[0] = atoi(argv[1]);
448 0 : iPipe[1] = atoi(argv[2]);
449 :
450 : // fd_pipe[0]: read, fd_pipe[0]: write
451 0 : fd_pipe[0] = (NSP_PIPE_FD) (sal_IntPtr) iPipe[0] ;
452 0 : fd_pipe[1] = (NSP_PIPE_FD) (sal_IntPtr) iPipe[1] ;
453 0 : NSP_Close_Pipe(fd_pipe[1]);
454 :
455 0 : if(iPipe[0] < 0)
456 : {
457 0 : debug_fprintf(NSP_LOG_APPEND, "print by nsplugin, command error: bad read file id:%s \n", iPipe[0]);
458 0 : return 0;
459 : }
460 0 : la_read_fd = fd_pipe[0];
461 :
462 : // the program path is provided only on unix, on windows the registry entry is used
463 0 : if ( argc > 4 )
464 0 : progdir = argv[4];
465 :
466 0 : Reference< lang::XMultiServiceFactory > xFactory = start_office(la_read_fd);
467 0 : if(!xFactory.is())
468 : {
469 0 : NSP_Close_Pipe(la_read_fd);
470 0 : return -1;
471 : }
472 : PLUGIN_MSG nMsg;
473 : int len;
474 : while(true)
475 : {
476 0 : memset(&nMsg, 0, sizeof(PLUGIN_MSG));
477 0 : len = NSP_ReadFromPipe(la_read_fd, (char*)&nMsg, sizeof(PLUGIN_MSG));
478 0 : if(len != sizeof(PLUGIN_MSG))
479 0 : break;
480 0 : debug_fprintf(NSP_LOG_APPEND, "Read message from pipe type %d \n", nMsg.msg_id);
481 0 : if(-1 == dispatchMsg(&nMsg, xFactory))
482 : {
483 0 : debug_fprintf(NSP_LOG_APPEND, "plugin will shutdown\n");
484 0 : break;
485 : }
486 : }
487 0 : NSP_Close_Pipe(la_read_fd);
488 0 : _exit(0);
489 : #ifndef _MSC_VER
490 0 : return EXIT_SUCCESS; // avoid warnings
491 : #endif
492 : }
493 :
494 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|