Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <config_folders.h>
21 :
22 : #include <helper/networkdomain.hxx>
23 :
24 : #include <cppuhelper/basemutex.hxx>
25 : #include <cppuhelper/compbase2.hxx>
26 : #include <cppuhelper/supportsservice.hxx>
27 : #include <unotools/configitem.hxx>
28 : #include <unotools/localfilehelper.hxx>
29 : #include <unotools/configmgr.hxx>
30 :
31 : #include <unotools/bootstrap.hxx>
32 : #include <osl/mutex.hxx>
33 : #include <osl/file.hxx>
34 : #include <osl/security.hxx>
35 : #include <osl/socket.hxx>
36 : #include <osl/process.h>
37 : #include <i18nlangtag/languagetag.hxx>
38 : #include <i18nlangtag/mslangid.hxx>
39 : #include <tools/link.hxx>
40 : #include <tools/urlobj.hxx>
41 : #include <tools/resmgr.hxx>
42 : #include <tools/wldcrd.hxx>
43 : #include <rtl/ustrbuf.hxx>
44 : #include <rtl/bootstrap.hxx>
45 :
46 : #include <officecfg/Office/Paths.hxx>
47 :
48 : #include <com/sun/star/lang/XServiceInfo.hpp>
49 : #include <com/sun/star/container/NoSuchElementException.hpp>
50 : #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
51 : #include <com/sun/star/util/XStringSubstitution.hpp>
52 :
53 : #include <boost/unordered_map.hpp>
54 : #include <string.h>
55 :
56 : using namespace com::sun::star::uno;
57 : using namespace com::sun::star::beans;
58 : using namespace com::sun::star::util;
59 : using namespace com::sun::star::lang;
60 : using namespace com::sun::star::container;
61 : using namespace framework;
62 :
63 : namespace {
64 :
65 : // Must be zero value based
66 : enum EnvironmentType
67 : {
68 : ET_HOST = 0 ,
69 : ET_YPDOMAIN ,
70 : ET_DNSDOMAIN ,
71 : ET_NTDOMAIN ,
72 : ET_OS ,
73 : ET_UNKNOWN ,
74 : ET_COUNT
75 : };
76 :
77 : // Must be zero value based
78 : enum OperatingSystem
79 : {
80 : OS_WINDOWS = 0,
81 : OS_UNIX ,
82 : OS_SOLARIS ,
83 : OS_LINUX ,
84 : OS_UNKNOWN ,
85 : OS_COUNT
86 : };
87 :
88 0 : struct SubstituteRule
89 : {
90 0 : SubstituteRule()
91 0 : : aEnvType(ET_UNKNOWN)
92 0 : {}
93 :
94 0 : SubstituteRule( const OUString& aVarName,
95 : const OUString& aValue,
96 : const com::sun::star::uno::Any& aVal,
97 : EnvironmentType aType )
98 : : aSubstVariable(aVarName)
99 : , aSubstValue(aValue)
100 : , aEnvValue(aVal)
101 0 : , aEnvType(aType)
102 0 : {}
103 :
104 : OUString aSubstVariable;
105 : OUString aSubstValue;
106 : com::sun::star::uno::Any aEnvValue;
107 : EnvironmentType aEnvType;
108 : };
109 :
110 : typedef boost::unordered_map<OUString, SubstituteRule, OUStringHash>
111 : SubstituteVariables;
112 :
113 : typedef std::vector< SubstituteRule > SubstituteRuleVector;
114 : class SubstitutePathVariables_Impl : public utl::ConfigItem
115 : {
116 : public:
117 : SubstitutePathVariables_Impl( const Link& aNotifyLink );
118 : virtual ~SubstitutePathVariables_Impl();
119 :
120 : static OperatingSystem GetOperatingSystemFromString( const OUString& );
121 : static EnvironmentType GetEnvTypeFromString( const OUString& );
122 :
123 : void GetSharePointsRules( SubstituteVariables& aSubstVarMap );
124 :
125 : /** is called from the ConfigManager before application ends or from the
126 : PropertyChangeListener if the sub tree broadcasts changes. */
127 : virtual void Notify( const com::sun::star::uno::Sequence< OUString >& aPropertyNames ) SAL_OVERRIDE;
128 : virtual void Commit() SAL_OVERRIDE;
129 :
130 : private:
131 : // Wrapper methods for low-level functions
132 : OperatingSystem GetOperatingSystem();
133 : const OUString& GetYPDomainName();
134 : const OUString& GetDNSDomainName();
135 : const OUString& GetNTDomainName();
136 : const OUString& GetHostName();
137 :
138 : bool FilterRuleSet( const SubstituteRuleVector& aRuleSet, SubstituteRule& aActiveRule );
139 :
140 : void ReadSharePointsFromConfiguration( com::sun::star::uno::Sequence< OUString >& aSharePointsSeq );
141 : void ReadSharePointRuleSetFromConfiguration( const OUString& aSharePointName,
142 : const OUString& aSharePointNodeName,
143 : SubstituteRuleVector& aRuleSet );
144 :
145 : // Stored values for domains and host
146 : bool m_bYPDomainRetrieved;
147 : OUString m_aYPDomain;
148 : bool m_bDNSDomainRetrieved;
149 : OUString m_aDNSDomain;
150 : bool m_bNTDomainRetrieved;
151 : OUString m_aNTDomain;
152 : bool m_bHostRetrieved;
153 : OUString m_aHost;
154 :
155 : Link m_aListenerNotify;
156 : const OUString m_aSharePointsNodeName;
157 : const OUString m_aDirPropertyName;
158 : const OUString m_aEnvPropertyName;
159 : const OUString m_aLevelSep;
160 : };
161 :
162 : enum PreDefVariable
163 : {
164 : PREDEFVAR_INST,
165 : PREDEFVAR_PROG,
166 : PREDEFVAR_USER,
167 : PREDEFVAR_WORK,
168 : PREDEFVAR_HOME,
169 : PREDEFVAR_TEMP,
170 : PREDEFVAR_PATH,
171 : PREDEFVAR_LANGID,
172 : PREDEFVAR_VLANG,
173 : PREDEFVAR_INSTPATH,
174 : PREDEFVAR_PROGPATH,
175 : PREDEFVAR_USERPATH,
176 : PREDEFVAR_INSTURL,
177 : PREDEFVAR_PROGURL,
178 : PREDEFVAR_USERURL,
179 : PREDEFVAR_WORKDIRURL,
180 : // New variable of hierachy service (#i32656#)
181 : PREDEFVAR_BASEINSTURL,
182 : PREDEFVAR_USERDATAURL,
183 : PREDEFVAR_BRANDBASEURL,
184 : PREDEFVAR_COUNT
185 : };
186 :
187 509 : struct PredefinedPathVariables
188 : {
189 : // Predefined variables supported by substitute variables
190 : LanguageType m_eLanguageType; // Lanuage type of Office
191 : OUString m_FixedVar[ PREDEFVAR_COUNT ]; // Variable value access by PreDefVariable
192 : OUString m_FixedVarNames[ PREDEFVAR_COUNT ]; // Variable name access by PreDefVariable
193 : };
194 :
195 : struct ReSubstFixedVarOrder
196 : {
197 : sal_Int32 nVarValueLength;
198 : PreDefVariable eVariable;
199 :
200 16260 : bool operator< ( const ReSubstFixedVarOrder& aFixedVarOrder ) const
201 : {
202 : // Reverse operator< to have high to low ordering
203 16260 : return ( nVarValueLength > aFixedVarOrder.nVarValueLength );
204 : }
205 : };
206 :
207 0 : struct ReSubstUserVarOrder
208 : {
209 : sal_Int32 nVarValueLength;
210 : OUString aVarName;
211 :
212 0 : bool operator< ( const ReSubstUserVarOrder& aUserVarOrder ) const
213 : {
214 : // Reverse operator< to have high to low ordering
215 0 : return ( nVarValueLength > aUserVarOrder.nVarValueLength );
216 : }
217 : };
218 :
219 : typedef std::list< ReSubstFixedVarOrder > ReSubstFixedVarOrderVector;
220 : typedef std::list< ReSubstUserVarOrder > ReSubstUserVarOrderVector;
221 : typedef ::cppu::WeakComponentImplHelper2<
222 : css::util::XStringSubstitution,
223 : css::lang::XServiceInfo > SubstitutePathVariables_BASE;
224 :
225 : class SubstitutePathVariables : private cppu::BaseMutex,
226 : public SubstitutePathVariables_BASE
227 : {
228 : friend class SubstitutePathVariables_Impl;
229 :
230 : public:
231 : SubstitutePathVariables( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& xContext );
232 : virtual ~SubstitutePathVariables();
233 :
234 2 : virtual OUString SAL_CALL getImplementationName()
235 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
236 : {
237 2 : return OUString("com.sun.star.comp.framework.PathSubstitution");
238 : }
239 :
240 0 : virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
241 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
242 : {
243 0 : return cppu::supportsService(this, ServiceName);
244 : }
245 :
246 0 : virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
247 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
248 : {
249 0 : css::uno::Sequence< OUString > aSeq(1);
250 0 : aSeq[0] = OUString("com.sun.star.util.PathSubstitution");
251 0 : return aSeq;
252 : }
253 :
254 : // XStringSubstitution
255 : virtual OUString SAL_CALL substituteVariables( const OUString& aText, sal_Bool bSubstRequired )
256 : throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
257 : virtual OUString SAL_CALL reSubstituteVariables( const OUString& aText )
258 : throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
259 : virtual OUString SAL_CALL getSubstituteVariableValue( const OUString& variable )
260 : throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
261 :
262 : protected:
263 : DECL_LINK(implts_ConfigurationNotify, void *);
264 :
265 : void SetPredefinedPathVariables();
266 : OUString ConvertOSLtoUCBURL( const OUString& aOSLCompliantURL ) const;
267 :
268 : // Special case (transient) values can change during runtime!
269 : // Don't store them in the pre defined struct
270 : OUString GetWorkPath() const;
271 : OUString GetWorkVariableValue() const;
272 : OUString GetPathVariableValue() const;
273 :
274 : OUString GetHomeVariableValue() const;
275 :
276 : // XStringSubstitution implementation methods
277 : OUString impl_substituteVariable( const OUString& aText, bool bSustRequired )
278 : throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
279 : OUString impl_reSubstituteVariables( const OUString& aText )
280 : throw (::com::sun::star::uno::RuntimeException);
281 : OUString impl_getSubstituteVariableValue( const OUString& variable )
282 : throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
283 :
284 : private:
285 : typedef boost::unordered_map<OUString, PreDefVariable, OUStringHash>
286 : VarNameToIndexMap;
287 :
288 : VarNameToIndexMap m_aPreDefVarMap; // Mapping from pre-def variable names to enum for array access
289 : SubstituteVariables m_aSubstVarMap; // Active rule set map indexed by variable name!
290 : PredefinedPathVariables m_aPreDefVars; // All predefined variables
291 : SubstitutePathVariables_Impl m_aImpl; // Implementation class that access the configuration
292 : ReSubstFixedVarOrderVector m_aReSubstFixedVarOrder; // To speed up resubstitution fixed variables (order for lookup)
293 : ReSubstUserVarOrderVector m_aReSubstUserVarOrder; // To speed up resubstitution user variables
294 : css::uno::Reference< css::uno::XComponentContext > m_xContext;
295 : };
296 :
297 : struct FixedVariable
298 : {
299 : const char* pVarName;
300 : sal_Int32 nStrLen;
301 : PreDefVariable nEnumValue;
302 : bool bAbsPath;
303 : };
304 :
305 : struct TableEntry
306 : {
307 : const char* pOSString;
308 : sal_Int32 nStrLen;
309 : };
310 :
311 : // Table with valid operating system strings
312 : // Name of the os as char* and the length
313 : // of the string
314 : static const TableEntry aOSTable[OS_COUNT] =
315 : {
316 : { RTL_CONSTASCII_STRINGPARAM("WINDOWS") },
317 : { RTL_CONSTASCII_STRINGPARAM("UNIX") },
318 : { RTL_CONSTASCII_STRINGPARAM("SOLARIS") },
319 : { RTL_CONSTASCII_STRINGPARAM("LINUX") },
320 : { RTL_CONSTASCII_STRINGPARAM("") } // unknown
321 : };
322 :
323 : // Table with valid environment variables
324 : // Name of the environment type as a char* and
325 : // the length of the string.
326 : static const TableEntry aEnvTable[ET_COUNT] =
327 : {
328 : { RTL_CONSTASCII_STRINGPARAM("HOST") },
329 : { RTL_CONSTASCII_STRINGPARAM("YPDOMAIN") },
330 : { RTL_CONSTASCII_STRINGPARAM("DNSDOMAIN") },
331 : { RTL_CONSTASCII_STRINGPARAM("NTDOMAIN") },
332 : { RTL_CONSTASCII_STRINGPARAM("OS") },
333 : { RTL_CONSTASCII_STRINGPARAM("") } // unknown
334 : };
335 :
336 : // Priority table for the environment types. Lower numbers define
337 : // a higher priority. Equal numbers has the same priority that means
338 : // that the first match wins!!
339 : static const sal_Int16 aEnvPrioTable[ET_COUNT] =
340 : {
341 : 1, // ET_HOST
342 : 2, // ET_IPDOMAIN
343 : 2, // ET_DNSDOMAIN
344 : 2, // ET_NTDOMAIN
345 : 3, // ET_OS
346 : 99, // ET_UNKNOWN
347 : };
348 :
349 : // Table with all fixed/predefined variables supported.
350 : static const FixedVariable aFixedVarTable[] =
351 : {
352 : { RTL_CONSTASCII_STRINGPARAM("$(inst)"), PREDEFVAR_INST, true },
353 : { RTL_CONSTASCII_STRINGPARAM("$(prog)"), PREDEFVAR_PROG, true },
354 : { RTL_CONSTASCII_STRINGPARAM("$(user)"), PREDEFVAR_USER, true },
355 : { RTL_CONSTASCII_STRINGPARAM("$(work)"), PREDEFVAR_WORK, true }, // Special variable (transient)!
356 : { RTL_CONSTASCII_STRINGPARAM("$(home)"), PREDEFVAR_HOME, true },
357 : { RTL_CONSTASCII_STRINGPARAM("$(temp)"), PREDEFVAR_TEMP, true },
358 : { RTL_CONSTASCII_STRINGPARAM("$(path)"), PREDEFVAR_PATH, true },
359 : { RTL_CONSTASCII_STRINGPARAM("$(langid)"), PREDEFVAR_LANGID, false },
360 : { RTL_CONSTASCII_STRINGPARAM("$(vlang)"), PREDEFVAR_VLANG, false },
361 : { RTL_CONSTASCII_STRINGPARAM("$(instpath)"), PREDEFVAR_INSTPATH, true },
362 : { RTL_CONSTASCII_STRINGPARAM("$(progpath)"), PREDEFVAR_PROGPATH, true },
363 : { RTL_CONSTASCII_STRINGPARAM("$(userpath)"), PREDEFVAR_USERPATH, true },
364 : { RTL_CONSTASCII_STRINGPARAM("$(insturl)"), PREDEFVAR_INSTURL, true },
365 : { RTL_CONSTASCII_STRINGPARAM("$(progurl)"), PREDEFVAR_PROGURL, true },
366 : { RTL_CONSTASCII_STRINGPARAM("$(userurl)"), PREDEFVAR_USERURL, true },
367 : { RTL_CONSTASCII_STRINGPARAM("$(workdirurl)"), PREDEFVAR_WORKDIRURL, true }, // Special variable (transient) and don't use for resubstitution!
368 : { RTL_CONSTASCII_STRINGPARAM("$(baseinsturl)"), PREDEFVAR_BASEINSTURL, true },
369 : { RTL_CONSTASCII_STRINGPARAM("$(userdataurl)"), PREDEFVAR_USERDATAURL, true },
370 : { RTL_CONSTASCII_STRINGPARAM("$(brandbaseurl)"),PREDEFVAR_BRANDBASEURL, true }
371 : };
372 :
373 : // Implementation helper classes
374 :
375 0 : OperatingSystem SubstitutePathVariables_Impl::GetOperatingSystemFromString( const OUString& aOSString )
376 : {
377 0 : for ( int i = 0; i < OS_COUNT; i++ )
378 : {
379 0 : if ( aOSString.equalsIgnoreAsciiCaseAsciiL( aOSTable[i].pOSString, aOSTable[i].nStrLen ))
380 0 : return (OperatingSystem)i;
381 : }
382 :
383 0 : return OS_UNKNOWN;
384 : }
385 :
386 0 : EnvironmentType SubstitutePathVariables_Impl::GetEnvTypeFromString( const OUString& aEnvTypeString )
387 : {
388 0 : for ( int i = 0; i < ET_COUNT; i++ )
389 : {
390 0 : if ( aEnvTypeString.equalsIgnoreAsciiCaseAsciiL( aEnvTable[i].pOSString, aEnvTable[i].nStrLen ))
391 0 : return (EnvironmentType)i;
392 : }
393 :
394 0 : return ET_UNKNOWN;
395 : }
396 :
397 307 : SubstitutePathVariables_Impl::SubstitutePathVariables_Impl( const Link& aNotifyLink ) :
398 : utl::ConfigItem( OUString( "Office.Substitution" )),
399 : m_bYPDomainRetrieved( false ),
400 : m_bDNSDomainRetrieved( false ),
401 : m_bNTDomainRetrieved( false ),
402 : m_bHostRetrieved( false ),
403 : m_aListenerNotify( aNotifyLink ),
404 : m_aSharePointsNodeName( OUString( "SharePoints" )),
405 : m_aDirPropertyName( OUString( "/Directory" )),
406 : m_aEnvPropertyName( OUString( "/Environment" )),
407 307 : m_aLevelSep( OUString( "/" ))
408 : {
409 : // Enable notification mechanism
410 : // We need it to get information about changes outside these class on our configuration branch
411 307 : Sequence< OUString > aNotifySeq( 1 );
412 307 : aNotifySeq[0] = "SharePoints";
413 307 : EnableNotification( aNotifySeq, true );
414 307 : }
415 :
416 202 : SubstitutePathVariables_Impl::~SubstitutePathVariables_Impl()
417 : {
418 202 : }
419 :
420 307 : void SubstitutePathVariables_Impl::GetSharePointsRules( SubstituteVariables& aSubstVarMap )
421 : {
422 307 : Sequence< OUString > aSharePointNames;
423 307 : ReadSharePointsFromConfiguration( aSharePointNames );
424 :
425 307 : if ( aSharePointNames.getLength() > 0 )
426 : {
427 0 : sal_Int32 nSharePoints = 0;
428 :
429 : // Read SharePoints container from configuration
430 0 : while ( nSharePoints < aSharePointNames.getLength() )
431 : {
432 0 : OUString aSharePointNodeName( m_aSharePointsNodeName );
433 0 : aSharePointNodeName += "/";
434 0 : aSharePointNodeName += aSharePointNames[ nSharePoints ];
435 :
436 0 : SubstituteRuleVector aRuleSet;
437 0 : ReadSharePointRuleSetFromConfiguration( aSharePointNames[ nSharePoints ], aSharePointNodeName, aRuleSet );
438 0 : if ( !aRuleSet.empty() )
439 : {
440 : // We have at minimum one rule. Filter the correct rule out of the rule set
441 : // and put into our SubstituteVariable map
442 0 : SubstituteRule aActiveRule;
443 0 : if ( FilterRuleSet( aRuleSet, aActiveRule ))
444 : {
445 : // We have found an active rule
446 0 : aActiveRule.aSubstVariable = aSharePointNames[ nSharePoints ];
447 : aSubstVarMap.insert( SubstituteVariables::value_type(
448 0 : aActiveRule.aSubstVariable, aActiveRule ));
449 0 : }
450 : }
451 0 : ++nSharePoints;
452 0 : }
453 307 : }
454 307 : }
455 :
456 0 : void SubstitutePathVariables_Impl::Notify( const com::sun::star::uno::Sequence< OUString >& /*aPropertyNames*/ )
457 : {
458 : // NOT implemented yet!
459 0 : }
460 :
461 0 : void SubstitutePathVariables_Impl::Commit()
462 : {
463 0 : }
464 :
465 0 : OperatingSystem SubstitutePathVariables_Impl::GetOperatingSystem()
466 : {
467 : #ifdef SOLARIS
468 : return OS_SOLARIS;
469 : #elif defined LINUX
470 0 : return OS_LINUX;
471 : #elif defined WIN32
472 : return OS_WINDOWS;
473 : #elif defined UNIX
474 : return OS_UNIX;
475 : #else
476 : return OS_UNKNOWN;
477 : #endif
478 : }
479 :
480 0 : const OUString& SubstitutePathVariables_Impl::GetYPDomainName()
481 : {
482 0 : if ( !m_bYPDomainRetrieved )
483 : {
484 0 : m_aYPDomain = NetworkDomain::GetYPDomainName().toAsciiLowerCase();
485 0 : m_bYPDomainRetrieved = true;
486 : }
487 :
488 0 : return m_aYPDomain;
489 : }
490 :
491 0 : const OUString& SubstitutePathVariables_Impl::GetDNSDomainName()
492 : {
493 0 : if ( !m_bDNSDomainRetrieved )
494 : {
495 0 : OUString aTemp;
496 0 : osl::SocketAddr aSockAddr;
497 : oslSocketResult aResult;
498 :
499 0 : OUString aHostName = GetHostName();
500 0 : osl::SocketAddr::resolveHostname( aHostName, aSockAddr );
501 0 : aTemp = aSockAddr.getHostname( &aResult );
502 :
503 : // DNS domain name begins after the first "."
504 0 : sal_Int32 nIndex = aTemp.indexOf( '.' );
505 0 : if ( nIndex >= 0 && aTemp.getLength() > nIndex+1 )
506 0 : m_aDNSDomain = aTemp.copy( nIndex+1 ).toAsciiLowerCase();
507 : else
508 0 : m_aDNSDomain = "";
509 :
510 0 : m_bDNSDomainRetrieved = true;
511 : }
512 :
513 0 : return m_aDNSDomain;
514 : }
515 :
516 0 : const OUString& SubstitutePathVariables_Impl::GetNTDomainName()
517 : {
518 0 : if ( !m_bNTDomainRetrieved )
519 : {
520 0 : m_aNTDomain = NetworkDomain::GetNTDomainName().toAsciiLowerCase();
521 0 : m_bNTDomainRetrieved = true;
522 : }
523 :
524 0 : return m_aNTDomain;
525 : }
526 :
527 0 : const OUString& SubstitutePathVariables_Impl::GetHostName()
528 : {
529 0 : if (!m_bHostRetrieved)
530 : {
531 : oslSocketResult aSocketResult;
532 0 : m_aHost = osl::SocketAddr::getLocalHostname( &aSocketResult ).toAsciiLowerCase();
533 : }
534 :
535 0 : return m_aHost;
536 : }
537 :
538 0 : bool SubstitutePathVariables_Impl::FilterRuleSet( const SubstituteRuleVector& aRuleSet, SubstituteRule& aActiveRule )
539 : {
540 0 : bool bResult = false;
541 :
542 0 : if ( !aRuleSet.empty() )
543 : {
544 0 : const sal_uInt32 nCount = aRuleSet.size();
545 :
546 0 : sal_Int16 nPrioCurrentRule = aEnvPrioTable[ ET_UNKNOWN ];
547 0 : for ( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
548 : {
549 0 : const SubstituteRule& aRule = aRuleSet[nIndex];
550 0 : EnvironmentType eEnvType = aRule.aEnvType;
551 :
552 : // Check if environment type has a higher priority than current one!
553 0 : if ( nPrioCurrentRule > aEnvPrioTable[eEnvType] )
554 : {
555 0 : switch ( eEnvType )
556 : {
557 : case ET_HOST:
558 : {
559 0 : OUString aHost = GetHostName();
560 0 : OUString aHostStr;
561 0 : aRule.aEnvValue >>= aHostStr;
562 0 : aHostStr = aHostStr.toAsciiLowerCase();
563 :
564 : // Pattern match if domain environment match
565 0 : WildCard aPattern(aHostStr);
566 0 : bool bMatch = aPattern.Matches(aHost);
567 0 : if ( bMatch )
568 : {
569 0 : aActiveRule = aRule;
570 0 : bResult = true;
571 0 : nPrioCurrentRule = aEnvPrioTable[eEnvType];
572 0 : }
573 : }
574 0 : break;
575 :
576 : case ET_YPDOMAIN:
577 : case ET_DNSDOMAIN:
578 : case ET_NTDOMAIN:
579 : {
580 0 : OUString aDomain;
581 0 : OUString aDomainStr;
582 0 : aRule.aEnvValue >>= aDomainStr;
583 0 : aDomainStr = aDomainStr.toAsciiLowerCase();
584 :
585 : // Retrieve the correct domain value
586 0 : if ( eEnvType == ET_YPDOMAIN )
587 0 : aDomain = GetYPDomainName();
588 0 : else if ( eEnvType == ET_DNSDOMAIN )
589 0 : aDomain = GetDNSDomainName();
590 : else
591 0 : aDomain = GetNTDomainName();
592 :
593 : // Pattern match if domain environment match
594 0 : WildCard aPattern(aDomainStr);
595 0 : bool bMatch = aPattern.Matches(aDomain);
596 0 : if ( bMatch )
597 : {
598 0 : aActiveRule = aRule;
599 0 : bResult = true;
600 0 : nPrioCurrentRule = aEnvPrioTable[eEnvType];
601 0 : }
602 : }
603 0 : break;
604 :
605 : case ET_OS:
606 : {
607 : // No pattern matching for OS type
608 0 : OperatingSystem eOSType = GetOperatingSystem();
609 :
610 0 : sal_Int16 nValue = 0;
611 0 : aRule.aEnvValue >>= nValue;
612 :
613 0 : bool bUnix = ( eOSType == OS_LINUX ) || ( eOSType == OS_SOLARIS );
614 0 : OperatingSystem eRuleOSType = (OperatingSystem)nValue;
615 :
616 : // Match if OS identical or rule is set to UNIX and OS is LINUX/SOLARIS!
617 0 : if (( eRuleOSType == eOSType ) || ( eRuleOSType == OS_UNIX && bUnix ))
618 : {
619 0 : aActiveRule = aRule;
620 0 : bResult = true;
621 0 : nPrioCurrentRule = aEnvPrioTable[eEnvType];
622 : }
623 : }
624 0 : break;
625 :
626 : case ET_UNKNOWN: // nothing to do
627 0 : break;
628 :
629 : default:
630 0 : break;
631 : }
632 : }
633 : }
634 : }
635 :
636 0 : return bResult;
637 : }
638 :
639 307 : void SubstitutePathVariables_Impl::ReadSharePointsFromConfiguration( Sequence< OUString >& aSharePointsSeq )
640 : {
641 : //returns all the names of all share point nodes
642 307 : aSharePointsSeq = GetNodeNames( m_aSharePointsNodeName );
643 307 : }
644 :
645 0 : void SubstitutePathVariables_Impl::ReadSharePointRuleSetFromConfiguration(
646 : const OUString& aSharePointName,
647 : const OUString& aSharePointNodeName,
648 : SubstituteRuleVector& rRuleSet )
649 : {
650 0 : Sequence< OUString > aSharePointMappingsNodeNames = GetNodeNames( aSharePointNodeName, utl::CONFIG_NAME_LOCAL_PATH );
651 :
652 0 : sal_Int32 nSharePointMapping = 0;
653 0 : while ( nSharePointMapping < aSharePointMappingsNodeNames.getLength() )
654 : {
655 0 : OUString aSharePointMapping( aSharePointNodeName );
656 0 : aSharePointMapping += m_aLevelSep;
657 0 : aSharePointMapping += aSharePointMappingsNodeNames[ nSharePointMapping ];
658 :
659 : // Read SharePointMapping
660 0 : OUString aDirValue;
661 0 : OUString aDirProperty( aSharePointMapping );
662 0 : aDirProperty += m_aDirPropertyName;
663 :
664 : // Read only the directory property
665 0 : Sequence< OUString > aDirPropertySeq( 1 );
666 0 : aDirPropertySeq[0] = aDirProperty;
667 :
668 0 : Sequence< Any > aValueSeq = GetProperties( aDirPropertySeq );
669 0 : if ( aValueSeq.getLength() == 1 )
670 0 : aValueSeq[0] >>= aDirValue;
671 :
672 : // Read the environment setting
673 0 : OUString aEnvUsed;
674 0 : OUString aEnvProperty( aSharePointMapping );
675 0 : aEnvProperty += m_aEnvPropertyName;
676 0 : Sequence< OUString > aEnvironmentVariable = GetNodeNames( aEnvProperty );
677 :
678 : // Filter the property which has a value set
679 0 : Sequence< OUString > aEnvUsedPropertySeq( aEnvironmentVariable.getLength() );
680 :
681 0 : OUString aEnvUsePropNameTemplate( aEnvProperty );
682 0 : aEnvUsePropNameTemplate += m_aLevelSep;
683 :
684 0 : for ( sal_Int32 nProperty = 0; nProperty < aEnvironmentVariable.getLength(); nProperty++ )
685 0 : aEnvUsedPropertySeq[nProperty] = aEnvUsePropNameTemplate + aEnvironmentVariable[nProperty];
686 :
687 0 : Sequence< Any > aEnvUsedValueSeq;
688 0 : aEnvUsedValueSeq = GetProperties( aEnvUsedPropertySeq );
689 :
690 0 : OUString aEnvUsedValue;
691 0 : for ( sal_Int32 nIndex = 0; nIndex < aEnvironmentVariable.getLength(); nIndex++ )
692 : {
693 0 : if ( aEnvUsedValueSeq[nIndex] >>= aEnvUsedValue )
694 : {
695 0 : aEnvUsed = aEnvironmentVariable[nIndex];
696 0 : break;
697 : }
698 : }
699 :
700 : // Decode the environment and optional the operatng system settings
701 0 : Any aEnvValue;
702 0 : EnvironmentType eEnvType = GetEnvTypeFromString( aEnvUsed );
703 0 : if ( eEnvType == ET_OS )
704 : {
705 0 : OperatingSystem eOSType = GetOperatingSystemFromString( aEnvUsedValue );
706 0 : aEnvValue <<= (sal_Int16)eOSType;
707 : }
708 : else
709 0 : aEnvValue <<= aEnvUsedValue;
710 :
711 : // Create rule struct and push it into the rule set
712 0 : SubstituteRule aRule( aSharePointName, aDirValue, aEnvValue, eEnvType );
713 0 : rRuleSet.push_back( aRule );
714 :
715 0 : ++nSharePointMapping;
716 0 : }
717 0 : }
718 :
719 307 : SubstitutePathVariables::SubstitutePathVariables( const Reference< XComponentContext >& xContext ) :
720 : SubstitutePathVariables_BASE(m_aMutex),
721 : m_aImpl( LINK( this, SubstitutePathVariables, implts_ConfigurationNotify )),
722 307 : m_xContext( xContext )
723 : {
724 : int i;
725 :
726 307 : SetPredefinedPathVariables();
727 307 : m_aImpl.GetSharePointsRules( m_aSubstVarMap );
728 :
729 : // Init the predefined/fixed variable to index hash map
730 6140 : for ( i = 0; i < PREDEFVAR_COUNT; i++ )
731 : {
732 : // Store variable name into struct of predefined/fixed variables
733 5833 : m_aPreDefVars.m_FixedVarNames[i] = OUString::createFromAscii( aFixedVarTable[i].pVarName );
734 :
735 : // Create hash map entry
736 : m_aPreDefVarMap.insert( VarNameToIndexMap::value_type(
737 5833 : m_aPreDefVars.m_FixedVarNames[i], aFixedVarTable[i].nEnumValue ) );
738 : }
739 :
740 : // Sort predefined/fixed variable to path length
741 6140 : for ( i = 0; i < PREDEFVAR_COUNT; i++ )
742 : {
743 5833 : if (( i != PREDEFVAR_WORKDIRURL ) && ( i != PREDEFVAR_PATH ))
744 : {
745 : // Special path variables, don't include into automatic resubstituion search!
746 : // $(workdirurl) is not allowed to resubstitute! This variable is the value of path settings entry
747 : // and it could be possible that it will be resubstituted by itself!!
748 : // Example: WORK_PATH=c:\test, $(workdirurl)=WORK_PATH => WORK_PATH=$(workdirurl) and this cannot be substituted!
749 : ReSubstFixedVarOrder aFixedVar;
750 5219 : aFixedVar.eVariable = aFixedVarTable[i].nEnumValue;
751 5219 : aFixedVar.nVarValueLength = m_aPreDefVars.m_FixedVar[(sal_Int32)aFixedVar.eVariable].getLength();
752 5219 : m_aReSubstFixedVarOrder.push_back( aFixedVar );
753 : }
754 : }
755 307 : m_aReSubstFixedVarOrder.sort();
756 :
757 : // Sort user variables to path length
758 307 : SubstituteVariables::const_iterator pIter;
759 307 : for ( pIter = m_aSubstVarMap.begin(); pIter != m_aSubstVarMap.end(); ++pIter )
760 : {
761 0 : ReSubstUserVarOrder aUserOrderVar;
762 0 : aUserOrderVar.aVarName = "$(" + pIter->second.aSubstVariable + ")";
763 0 : aUserOrderVar.nVarValueLength = pIter->second.aSubstVariable.getLength();
764 0 : m_aReSubstUserVarOrder.push_back( aUserOrderVar );
765 0 : }
766 307 : m_aReSubstUserVarOrder.sort();
767 307 : }
768 :
769 404 : SubstitutePathVariables::~SubstitutePathVariables()
770 : {
771 404 : }
772 :
773 : // XStringSubstitution
774 26248 : OUString SAL_CALL SubstitutePathVariables::substituteVariables( const OUString& aText, sal_Bool bSubstRequired )
775 : throw ( NoSuchElementException, RuntimeException, std::exception )
776 : {
777 26248 : osl::MutexGuard g(rBHelper.rMutex);
778 26248 : return impl_substituteVariable( aText, bSubstRequired );
779 : }
780 :
781 134 : OUString SAL_CALL SubstitutePathVariables::reSubstituteVariables( const OUString& aText )
782 : throw ( RuntimeException, std::exception )
783 : {
784 134 : osl::MutexGuard g(rBHelper.rMutex);
785 134 : return impl_reSubstituteVariables( aText );
786 : }
787 :
788 4 : OUString SAL_CALL SubstitutePathVariables::getSubstituteVariableValue( const OUString& aVariable )
789 : throw ( NoSuchElementException, RuntimeException, std::exception )
790 : {
791 4 : osl::MutexGuard g(rBHelper.rMutex);
792 4 : return impl_getSubstituteVariableValue( aVariable );
793 : }
794 :
795 : // protected methods
796 :
797 0 : IMPL_LINK_NOARG(SubstitutePathVariables, implts_ConfigurationNotify)
798 : {
799 : /* SAFE AREA ----------------------------------------------------------------------------------------------- */
800 0 : osl::MutexGuard g(rBHelper.rMutex);
801 :
802 0 : return 0;
803 : }
804 :
805 1976 : OUString SubstitutePathVariables::ConvertOSLtoUCBURL( const OUString& aOSLCompliantURL ) const
806 : {
807 1976 : OUString aResult;
808 3952 : OUString aTemp;
809 :
810 1976 : osl::FileBase::getSystemPathFromFileURL( aOSLCompliantURL, aTemp );
811 1976 : utl::LocalFileHelper::ConvertPhysicalNameToURL( aTemp, aResult );
812 :
813 : // Not all OSL URL's can be mapped to UCB URL's!
814 1976 : if ( aResult.isEmpty() )
815 0 : return aOSLCompliantURL;
816 : else
817 3952 : return aResult;
818 : }
819 :
820 307 : OUString SubstitutePathVariables::GetWorkPath() const
821 : {
822 307 : OUString aWorkPath;
823 614 : css::uno::Reference< css::container::XHierarchicalNameAccess > xPaths(officecfg::Office::Paths::Paths::get(m_xContext), css::uno::UNO_QUERY_THROW);
824 307 : if (!(xPaths->getByHierarchicalName("['Work']/WritePath") >>= aWorkPath))
825 : // fallback in case config layer does not return an useable work dir value.
826 0 : aWorkPath = GetWorkVariableValue();
827 :
828 614 : return aWorkPath;
829 : }
830 :
831 1055 : OUString SubstitutePathVariables::GetWorkVariableValue() const
832 : {
833 1055 : OUString aWorkPath;
834 2110 : boost::optional<OUString> x(officecfg::Office::Paths::Variables::Work::get(m_xContext));
835 1055 : if (!x)
836 : {
837 : // fallback to $HOME in case platform dependent config layer does not return
838 : // an usuable work dir value.
839 1055 : osl::Security aSecurity;
840 1055 : aSecurity.getHomeDir( aWorkPath );
841 : }
842 : else
843 0 : aWorkPath = x.get();
844 2110 : return ConvertOSLtoUCBURL( aWorkPath );
845 : }
846 :
847 307 : OUString SubstitutePathVariables::GetHomeVariableValue() const
848 : {
849 307 : osl::Security aSecurity;
850 614 : OUString aHomePath;
851 :
852 307 : aSecurity.getHomeDir( aHomePath );
853 614 : return ConvertOSLtoUCBURL( aHomePath );
854 : }
855 :
856 307 : OUString SubstitutePathVariables::GetPathVariableValue() const
857 : {
858 :
859 307 : OUString aRetStr;
860 307 : const char* pEnv = getenv( "PATH" );
861 :
862 307 : if ( pEnv )
863 : {
864 307 : const int PATH_EXTEND_FACTOR = 120;
865 307 : OUString aTmp;
866 614 : OUString aPathList( pEnv, strlen( pEnv ), osl_getThreadTextEncoding() );
867 614 : OUStringBuffer aPathStrBuffer( aPathList.getLength() * PATH_EXTEND_FACTOR / 100 );
868 :
869 307 : bool bAppendSep = false;
870 307 : sal_Int32 nToken = 0;
871 2456 : do
872 : {
873 2456 : OUString sToken = aPathList.getToken(0, SAL_PATHSEPARATOR, nToken);
874 2456 : if (!sToken.isEmpty())
875 : {
876 2456 : osl::FileBase::getFileURLFromSystemPath( sToken, aTmp );
877 2456 : if ( bAppendSep )
878 2149 : aPathStrBuffer.appendAscii( ";" ); // Office uses ';' as path separator
879 2456 : aPathStrBuffer.append( aTmp );
880 2456 : bAppendSep = true;
881 2456 : }
882 : }
883 2456 : while(nToken>=0);
884 :
885 614 : aRetStr = aPathStrBuffer.makeStringAndClear();
886 : }
887 :
888 307 : return aRetStr;
889 : }
890 :
891 26248 : OUString SubstitutePathVariables::impl_substituteVariable( const OUString& rText, bool bSubstRequired )
892 : throw ( NoSuchElementException, RuntimeException )
893 : {
894 : // This is maximal recursive depth supported!
895 26248 : const sal_Int32 nMaxRecursiveDepth = 8;
896 :
897 26248 : OUString aWorkText = rText;
898 26248 : OUString aResult;
899 :
900 : // Use vector with strings to detect endless recursions!
901 52496 : std::vector< OUString > aEndlessRecursiveDetector;
902 :
903 : // Search for first occurrence of "$(...".
904 26248 : sal_Int32 nDepth = 0;
905 26248 : bool bSubstitutionCompleted = false;
906 26248 : sal_Int32 nPosition = aWorkText.indexOf( "$(" );
907 26248 : sal_Int32 nLength = 0; // = count of letters from "$(" to ")" in string
908 26248 : bool bVarNotSubstituted = false;
909 :
910 : // Have we found any variable like "$(...)"?
911 26248 : if ( nPosition != -1 )
912 : {
913 : // Yes; Get length of found variable.
914 : // If no ")" was found - nLength is set to 0 by default! see before.
915 22391 : sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition );
916 22391 : if ( nEndPosition != -1 )
917 22391 : nLength = nEndPosition - nPosition + 1;
918 : }
919 :
920 : // Is there something to replace ?
921 26248 : bool bWorkRetrieved = false;
922 26248 : bool bWorkDirURLRetrieved = false;
923 52512 : while ( !bSubstitutionCompleted && nDepth < nMaxRecursiveDepth )
924 : {
925 76157 : while ( ( nPosition != -1 ) && ( nLength > 3 ) ) // "$(" ")"
926 : {
927 : // YES; Get the next variable for replace.
928 23633 : sal_Int32 nReplaceLength = 0;
929 23633 : OUString aReplacement;
930 47266 : OUString aSubString = aWorkText.copy( nPosition, nLength );
931 47266 : OUString aSubVarString;
932 :
933 : // Path variables are not case sensitive!
934 23633 : aSubVarString = aSubString.toAsciiLowerCase();
935 23633 : VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( aSubVarString );
936 23633 : if ( pNTOIIter != m_aPreDefVarMap.end() )
937 : {
938 : // Fixed/Predefined variable found
939 23617 : PreDefVariable nIndex = (PreDefVariable)pNTOIIter->second;
940 :
941 : // Determine variable value and length from array/table
942 23617 : if ( nIndex == PREDEFVAR_WORK && !bWorkRetrieved )
943 : {
944 : // Transient value, retrieve it again
945 614 : m_aPreDefVars.m_FixedVar[ (PreDefVariable)nIndex ] = GetWorkVariableValue();
946 614 : bWorkRetrieved = true;
947 : }
948 23003 : else if ( nIndex == PREDEFVAR_WORKDIRURL && !bWorkDirURLRetrieved )
949 : {
950 : // Transient value, retrieve it again
951 0 : m_aPreDefVars.m_FixedVar[ (PreDefVariable)nIndex ] = GetWorkPath();
952 0 : bWorkDirURLRetrieved = true;
953 : }
954 :
955 : // Check preconditions to substitue path variables.
956 : // 1. A path variable can only be substituted if it follows a ';'!
957 : // 2. It's located exactly at the start of the string being substituted!
958 24845 : if (( aFixedVarTable[ int( nIndex ) ].bAbsPath && (( nPosition == 0 ) || (( nPosition > 0 ) && ( aWorkText[nPosition-1] == ';')))) ||
959 1228 : ( !aFixedVarTable[ int( nIndex ) ].bAbsPath ))
960 : {
961 23617 : aReplacement = m_aPreDefVars.m_FixedVar[ (PreDefVariable)nIndex ];
962 23617 : nReplaceLength = nLength;
963 : }
964 : }
965 : else
966 : {
967 : // Extract the variable name and try to find in the user defined variable set
968 16 : OUString aVarName = aSubString.copy( 2, nLength-3 );
969 16 : SubstituteVariables::const_iterator pIter = m_aSubstVarMap.find( aVarName );
970 16 : if ( pIter != m_aSubstVarMap.end() )
971 : {
972 : // Found.
973 0 : aReplacement = pIter->second.aSubstValue;
974 0 : nReplaceLength = nLength;
975 16 : }
976 : }
977 :
978 : // Have we found something to replace?
979 23633 : if ( nReplaceLength > 0 )
980 : {
981 : // Yes ... then do it.
982 23617 : aWorkText = aWorkText.replaceAt( nPosition, nReplaceLength, aReplacement );
983 : }
984 : else
985 : {
986 : // Variable not known
987 16 : bVarNotSubstituted = true;
988 16 : nPosition += nLength;
989 : }
990 :
991 : // Step after replaced text! If no text was replaced (unknown variable!),
992 : // length of aReplacement is 0 ... and we don't step then.
993 23633 : nPosition += aReplacement.getLength();
994 :
995 : // We must control index in string before call something at OUString!
996 : // The OUString-implementation don't do it for us :-( but the result is not defined otherwise.
997 23633 : if ( nPosition + 1 > aWorkText.getLength() )
998 : {
999 : // Position is out of range. Break loop!
1000 3256 : nPosition = -1;
1001 3256 : nLength = 0;
1002 : }
1003 : else
1004 : {
1005 : // Else; Position is valid. Search for next variable to replace.
1006 20377 : nPosition = aWorkText.indexOf( "$(", nPosition );
1007 : // Have we found any variable like "$(...)"?
1008 20377 : if ( nPosition != -1 )
1009 : {
1010 : // Yes; Get length of found variable. If no ")" was found - nLength must set to 0!
1011 1228 : nLength = 0;
1012 1228 : sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition );
1013 1228 : if ( nEndPosition != -1 )
1014 1228 : nLength = nEndPosition - nPosition + 1;
1015 : }
1016 : }
1017 23633 : }
1018 :
1019 26262 : nPosition = aWorkText.indexOf( "$(" );
1020 26262 : if ( nPosition == -1 )
1021 : {
1022 26246 : bSubstitutionCompleted = true;
1023 26246 : break; // All variables are substituted
1024 : }
1025 : else
1026 : {
1027 : // Check for recursion
1028 16 : const sal_uInt32 nCount = aEndlessRecursiveDetector.size();
1029 16 : for ( sal_uInt32 i=0; i < nCount; i++ )
1030 : {
1031 14 : if ( aEndlessRecursiveDetector[i] == aWorkText )
1032 : {
1033 14 : if ( bVarNotSubstituted )
1034 14 : break; // Not all variables could be substituted!
1035 : else
1036 : {
1037 0 : nDepth = nMaxRecursiveDepth;
1038 0 : break; // Recursion detected!
1039 : }
1040 : }
1041 : }
1042 :
1043 16 : aEndlessRecursiveDetector.push_back( aWorkText );
1044 :
1045 : // Initialize values for next
1046 16 : sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition );
1047 16 : if ( nEndPosition != -1 )
1048 16 : nLength = nEndPosition - nPosition + 1;
1049 16 : bVarNotSubstituted = false;
1050 16 : ++nDepth;
1051 : }
1052 : }
1053 :
1054 : // Fill return value with result
1055 26248 : if ( bSubstitutionCompleted )
1056 : {
1057 : // Substitution successful!
1058 26246 : aResult = aWorkText;
1059 : }
1060 : else
1061 : {
1062 : // Substitution not successful!
1063 2 : if ( nDepth == nMaxRecursiveDepth )
1064 : {
1065 : // recursion depth reached!
1066 2 : if ( bSubstRequired )
1067 : {
1068 2 : OUString aMsg( "Endless recursion detected. Cannot substitute variables!" );
1069 2 : throw NoSuchElementException( aMsg, (cppu::OWeakObject *)this );
1070 : }
1071 : else
1072 0 : aResult = rText;
1073 : }
1074 : else
1075 : {
1076 : // variable in text but unknown!
1077 0 : if ( bSubstRequired )
1078 : {
1079 0 : OUString aMsg( "Unknown variable found!" );
1080 0 : throw NoSuchElementException( aMsg, (cppu::OWeakObject *)this );
1081 : }
1082 : else
1083 0 : aResult = aWorkText;
1084 : }
1085 : }
1086 :
1087 52494 : return aResult;
1088 : }
1089 :
1090 134 : OUString SubstitutePathVariables::impl_reSubstituteVariables( const OUString& rURL )
1091 : throw ( RuntimeException )
1092 : {
1093 134 : OUString aURL;
1094 :
1095 268 : INetURLObject aUrl( rURL );
1096 134 : if ( !aUrl.HasError() )
1097 134 : aURL = aUrl.GetMainURL( INetURLObject::NO_DECODE );
1098 : else
1099 : {
1100 : // Convert a system path to a UCB compliant URL before resubstitution
1101 0 : OUString aTemp;
1102 0 : if ( osl::FileBase::getFileURLFromSystemPath( rURL, aTemp ) == osl::FileBase::E_None )
1103 : {
1104 0 : aTemp = ConvertOSLtoUCBURL( aTemp );
1105 0 : if ( !aTemp.isEmpty() )
1106 : {
1107 0 : aURL = INetURLObject( aTemp ).GetMainURL( INetURLObject::NO_DECODE );
1108 0 : if( aURL.isEmpty() )
1109 0 : return rURL;
1110 : }
1111 : else
1112 0 : return rURL;
1113 : }
1114 : else
1115 : {
1116 : // rURL is not a valid URL nor a osl system path. Give up and return error!
1117 0 : return rURL;
1118 0 : }
1119 : }
1120 :
1121 : // Get transient predefined path variable $(work) value before starting resubstitution
1122 134 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
1123 :
1124 : for (;;)
1125 : {
1126 266 : bool bVariableFound = false;
1127 :
1128 7632 : for (ReSubstFixedVarOrderVector::const_iterator i(
1129 266 : m_aReSubstFixedVarOrder.begin());
1130 5088 : i != m_aReSubstFixedVarOrder.end(); ++i)
1131 : {
1132 2410 : OUString aValue = m_aPreDefVars.m_FixedVar[i->eVariable];
1133 2410 : sal_Int32 nPos = aURL.indexOf( aValue );
1134 2410 : if ( nPos >= 0 )
1135 : {
1136 132 : bool bMatch = true;
1137 264 : if ( i->eVariable == PREDEFVAR_LANGID ||
1138 132 : i->eVariable == PREDEFVAR_VLANG )
1139 : {
1140 : // Special path variables as they can occur in the middle of a path. Only match if they
1141 : // describe a whole directory and not only a substring of a directory!
1142 0 : const sal_Unicode* pStr = aURL.getStr();
1143 :
1144 0 : if ( nPos > 0 )
1145 0 : bMatch = ( aURL[ nPos-1 ] == '/' );
1146 :
1147 0 : if ( bMatch )
1148 : {
1149 0 : if ( nPos + aValue.getLength() < aURL.getLength() )
1150 0 : bMatch = ( pStr[ nPos + aValue.getLength() ] == '/' );
1151 : }
1152 : }
1153 :
1154 132 : if ( bMatch )
1155 : {
1156 264 : aURL = aURL.replaceAt(
1157 : nPos, aValue.getLength(),
1158 264 : m_aPreDefVars.m_FixedVarNames[i->eVariable]);
1159 132 : bVariableFound = true; // Resubstitution not finished yet!
1160 132 : break;
1161 : }
1162 : }
1163 2278 : }
1164 :
1165 : // This part can be iteratered more than one time as variables can contain variables again!
1166 798 : for (ReSubstUserVarOrderVector::const_iterator i(
1167 266 : m_aReSubstUserVarOrder.begin());
1168 532 : i != m_aReSubstUserVarOrder.end(); ++i)
1169 : {
1170 0 : OUString aVarValue = i->aVarName;
1171 0 : sal_Int32 nPos = aURL.indexOf( aVarValue );
1172 0 : if ( nPos >= 0 )
1173 : {
1174 0 : aURL = aURL.replaceAt(
1175 0 : nPos, aVarValue.getLength(), "$(" + aVarValue + ")");
1176 0 : bVariableFound = true; // Resubstitution not finished yet!
1177 : }
1178 0 : }
1179 :
1180 266 : if ( !bVariableFound )
1181 : {
1182 134 : return aURL;
1183 : }
1184 266 : }
1185 : }
1186 :
1187 : // This method support both request schemes "$("<varname>")" or "<varname>".
1188 4 : OUString SubstitutePathVariables::impl_getSubstituteVariableValue( const OUString& rVariable )
1189 : throw ( NoSuchElementException, RuntimeException )
1190 : {
1191 4 : OUString aVariable;
1192 :
1193 4 : sal_Int32 nPos = rVariable.indexOf( "$(" );
1194 4 : if ( nPos == -1 )
1195 : {
1196 : // Prepare variable name before hash map access
1197 0 : aVariable = "$(" + rVariable + ")";
1198 : }
1199 :
1200 4 : VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( ( nPos == -1 ) ? aVariable : rVariable );
1201 :
1202 : // Fixed/Predefined variable
1203 4 : if ( pNTOIIter != m_aPreDefVarMap.end() )
1204 : {
1205 2 : PreDefVariable nIndex = (PreDefVariable)pNTOIIter->second;
1206 2 : return m_aPreDefVars.m_FixedVar[(sal_Int32)nIndex];
1207 : }
1208 : else
1209 : {
1210 : // Prepare variable name before hash map access
1211 2 : if ( nPos >= 0 )
1212 : {
1213 2 : if ( rVariable.getLength() > 3 )
1214 2 : aVariable = rVariable.copy( 2, rVariable.getLength() - 3 );
1215 : else
1216 : {
1217 0 : OUString aExceptionText("Unknown variable!");
1218 0 : throw NoSuchElementException(aExceptionText, (cppu::OWeakObject *)this);
1219 : }
1220 : }
1221 : else
1222 0 : aVariable = rVariable;
1223 :
1224 : // User defined variable
1225 2 : SubstituteVariables::const_iterator pIter = m_aSubstVarMap.find( aVariable );
1226 2 : if ( pIter != m_aSubstVarMap.end() )
1227 : {
1228 : // found!
1229 0 : return pIter->second.aSubstValue;
1230 : }
1231 :
1232 2 : OUString aExceptionText("Unknown variable!");
1233 2 : throw NoSuchElementException(aExceptionText, (cppu::OWeakObject *)this);
1234 4 : }
1235 : }
1236 :
1237 307 : void SubstitutePathVariables::SetPredefinedPathVariables()
1238 : {
1239 :
1240 307 : m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] = "$BRAND_BASE_DIR";
1241 : rtl::Bootstrap::expandMacros(
1242 307 : m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL]);
1243 :
1244 : // Get inspath and userpath from bootstrap mechanism in every case as file URL
1245 : ::utl::Bootstrap::PathStatus aState;
1246 307 : OUString sVal;
1247 :
1248 307 : aState = utl::Bootstrap::locateUserData( sVal );
1249 : //There can be the valid case that there is no user installation.
1250 : //TODO: Is that still the case? (With OOo 3.4, "unopkg sync" was run as part
1251 : // of the setup. Then no user installation was required.)
1252 : //Therefore we do not assert here.
1253 : // It's not possible to detect when an empty value would actually be used.
1254 : // (note: getenv is a hack to detect if we're running in a unit test)
1255 307 : if (aState == ::utl::Bootstrap::PATH_EXISTS || getenv("SRC_ROOT")) {
1256 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ] = ConvertOSLtoUCBURL( sVal );
1257 : }
1258 :
1259 : // Set $(inst), $(instpath), $(insturl)
1260 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ] = m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL];
1261 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
1262 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_INST ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
1263 : // New variable of hierachy service (#i32656#)
1264 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_BASEINSTURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
1265 :
1266 : // Set $(user), $(userpath), $(userurl)
1267 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
1268 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_USER ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
1269 : // New variable of hierachy service (#i32656#)
1270 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERDATAURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
1271 :
1272 : // Detect the program directory
1273 : // Set $(prog), $(progpath), $(progurl)
1274 : INetURLObject aProgObj(
1275 614 : m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] );
1276 307 : if ( !aProgObj.HasError() && aProgObj.insertName( OUString(LIBO_BIN_FOLDER) ) )
1277 : {
1278 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ] = aProgObj.GetMainURL(INetURLObject::NO_DECODE);
1279 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ];
1280 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROG ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ];
1281 : }
1282 :
1283 : // Detect the language type of the current office
1284 307 : m_aPreDefVars.m_eLanguageType = LANGUAGE_ENGLISH_US;
1285 614 : OUString aLocaleStr( utl::ConfigManager::getLocale() );
1286 307 : m_aPreDefVars.m_eLanguageType = LanguageTag::convertToLanguageTypeWithFallback( aLocaleStr );
1287 : // We used to have an else branch here with a SAL_WARN, but that
1288 : // always fired in some unit tests when this code was built with
1289 : // debug=t, so it seems fairly pointless, especially as
1290 : // m_aPreDefVars.m_eLanguageType has been initialized to a
1291 : // default value above anyway.
1292 :
1293 : // Set $(vlang)
1294 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_VLANG ] = aLocaleStr;
1295 :
1296 : // Set $(langid)
1297 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_LANGID ] = OUString::number( m_aPreDefVars.m_eLanguageType );
1298 :
1299 : // Set the other pre defined path variables
1300 : // Set $(work)
1301 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
1302 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_HOME ] = GetHomeVariableValue();
1303 :
1304 : // Set $(workdirurl) this is the value of the path PATH_WORK which doesn't make sense
1305 : // anymore because the path settings service has this value! It can deliver this value more
1306 : // quickly than the substitution service!
1307 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORKDIRURL ] = GetWorkPath();
1308 :
1309 : // Set $(path) variable
1310 307 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_PATH ] = GetPathVariableValue();
1311 :
1312 : // Set $(temp)
1313 614 : OUString aTmp;
1314 307 : osl::FileBase::getTempDirURL( aTmp );
1315 614 : m_aPreDefVars.m_FixedVar[ PREDEFVAR_TEMP ] = ConvertOSLtoUCBURL( aTmp );
1316 307 : }
1317 :
1318 307 : struct Instance {
1319 307 : explicit Instance(
1320 : css::uno::Reference<css::uno::XComponentContext> const & context):
1321 : instance(
1322 307 : static_cast<cppu::OWeakObject *>(new SubstitutePathVariables(context)))
1323 : {
1324 307 : }
1325 :
1326 : css::uno::Reference<css::uno::XInterface> instance;
1327 : };
1328 :
1329 : struct Singleton:
1330 : public rtl::StaticWithArg<
1331 : Instance, css::uno::Reference<css::uno::XComponentContext>, Singleton>
1332 : {};
1333 :
1334 : }
1335 :
1336 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
1337 11622 : com_sun_star_comp_framework_PathSubstitution_get_implementation(
1338 : css::uno::XComponentContext *context,
1339 : css::uno::Sequence<css::uno::Any> const &)
1340 : {
1341 : return cppu::acquire(static_cast<cppu::OWeakObject *>(
1342 11622 : Singleton::get(context).instance.get()));
1343 : }
1344 :
1345 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|