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