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: */
|