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