1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
30 
31 //_________________________________________________________________________________________________________________
32 //      my own includes
33 //_________________________________________________________________________________________________________________
34 #include "services/substitutepathvars.hxx"
35 #include <threadhelp/resetableguard.hxx>
36 #include <helper/networkdomain.hxx>
37 #include "services.h"
38 
39 //_________________________________________________________________________________________________________________
40 //      interface includes
41 //_________________________________________________________________________________________________________________
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 
44 //_________________________________________________________________________________________________________________
45 //      includes of other projects
46 //_________________________________________________________________________________________________________________
47 #include <unotools/configitem.hxx>
48 #include <unotools/localfilehelper.hxx>
49 #include <unotools/configmgr.hxx>
50 
51 #ifndef _UTL_BOOTSTRAP_HXX_
52 #include <unotools/bootstrap.hxx>
53 #endif
54 #include <osl/mutex.hxx>
55 #include <osl/file.hxx>
56 #include <osl/security.hxx>
57 #include <osl/socket.hxx>
58 #include <vos/process.hxx>
59 #include <i18npool/mslangid.hxx>
60 #include <tools/urlobj.hxx>
61 #include <tools/resmgr.hxx>
62 #include <tools/debug.hxx>
63 #include <tools/wldcrd.hxx>
64 #include <rtl/ustrbuf.hxx>
65 #include <rtl/bootstrap.hxx>
66 
67 #include <comphelper/configurationhelper.hxx>
68 
69 #include <string.h>
70 
71 //_________________________________________________________________________________________________________________
72 //      Defines
73 //_________________________________________________________________________________________________________________
74 //
75 
76 #define STRPOS_NOTFOUND                  (sal_Int32)-1
77 
78 #define ASCII_STR( val )                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( val ))
79 
80 #define SEARCHPATH_DELIMITER             ';'
81 
82 // Variable start/end characters
83 #define SIGN_STARTVARIABLE               ASCII_STR("$(")
84 #define SIGN_ENDVARIABLE                 ASCII_STR(")")
85 
86 // Length of SUBSTITUTE_... to replace it with real values.
87 #define REPLACELENGTH_INST               7
88 #define REPLACELENGTH_PROG               7
89 #define REPLACELENGTH_USER               7
90 #define REPLACELENGTH_WORK               7
91 #define REPLACELENGTH_HOME               7
92 #define REPLACELENGTH_TEMP               7
93 #define REPLACELENGTH_PATH               7
94 #define REPLACELENGTH_INSTPATH          11
95 #define REPLACELENGTH_PROGPATH          11
96 #define REPLACELENGTH_USERPATH          11
97 #define REPLACELENGTH_INSTURL           10
98 #define REPLACELENGTH_PROGURL           10
99 #define REPLACELENGTH_USERURL           10
100 #define REPLACELENGTH_PATH               7
101 #define REPLACELENGTH_LANG               7
102 #define REPLACELENGTH_LANGID             9
103 #define REPLACELENGTH_VLANG              8
104 #define REPLACELENGTH_WORKDIRURL        13
105 // --> PB 2004-10-27 #i32656# - new variable of hierachy service
106 #define REPLACELENGTH_BASEINSTURL       14
107 #define REPLACELENGTH_USERDATAURL       14
108 // <--
109 
110 // Name of the pre defined path variables
111 #define VARIABLE_INST                                   "$(inst)"
112 #define VARIABLE_PROG                                   "$(prog)"
113 #define VARIABLE_USER                                   "$(user)"
114 #define VARIABLE_WORK                                   "$(work)"
115 #define VARIABLE_HOME                                   "$(home)"
116 #define VARIABLE_TEMP                                   "$(temp)"
117 #define VARIABLE_PATH                                   "$(path)"
118 #define VARIABLE_LANG                                   "$(lang)"
119 #define VARIABLE_LANGID                                 "$(langid)"
120 #define VARIABLE_VLANG                                  "$(vlang)"
121 #define VARIABLE_INSTPATH                               "$(instpath)"
122 #define VARIABLE_PROGPATH                               "$(progpath)"
123 #define VARIABLE_USERPATH                               "$(userpath)"
124 #define VARIABLE_INSTURL                                "$(insturl)"
125 #define VARIABLE_PROGURL                                "$(progurl)"
126 #define VARIABLE_USERURL                                "$(userurl)"
127 #define VARIABLE_WORKDIRURL                             "$(workdirurl)"
128 // --> PB 2004-10-27 #i32656# - new variable of hierachy service
129 #define VARIABLE_BASEINSTURL                            "$(baseinsturl)"
130 #define VARIABLE_USERDATAURL                            "$(userdataurl)"
131 // <--
132 #define VARIABLE_BRANDBASEURL                           "$(brandbaseurl)"
133 
134 using namespace com::sun::star::uno;
135 using namespace com::sun::star::beans;
136 using namespace com::sun::star::util;
137 using namespace com::sun::star::lang;
138 using namespace com::sun::star::container;
139 
140 //_________________________________________________________________________________________________________________
141 //      Namespace
142 //_________________________________________________________________________________________________________________
143 //
144 
145 namespace framework
146 {
147 
148 struct FixedVariable
149 {
150     const char*     pVarName;
151     PreDefVariable  nEnumValue;
152     int             nStrLen;
153     bool            bAbsPath;
154 };
155 
156 struct TableEntry
157 {
158     const char* pOSString;
159     int         nStrLen;
160 };
161 
162 // Table with valid operating system strings
163 // Name of the os as char* and the length
164 // of the string
165 static TableEntry aOSTable[OS_COUNT] =
166 {
167     { "WINDOWS"     ,       7       },
168     { "UNIX"        ,       4       },
169     { "SOLARIS"     ,       7       },
170     { "LINUX"       ,       5       },
171     { ""            ,       0       }       // unknown
172 };
173 
174 // Table with valid environment variables
175 // Name of the environment type as a char* and
176 // the length of the string.
177 static TableEntry aEnvTable[ET_COUNT] =
178 {
179     { "HOST"        ,       4       },
180     { "YPDOMAIN"    ,       8       },
181     { "DNSDOMAIN"   ,       9       },
182     { "NTDOMAIN"    ,       8       },
183     { "OS"          ,       2       },
184     { ""            ,       0       } // unknown
185 };
186 
187 // Priority table for the environment types. Lower numbers define
188 // a higher priority. Equal numbers has the same priority that means
189 // that the first match wins!!
190 static sal_Int16 aEnvPrioTable[ET_COUNT] =
191 {
192     1,      // ET_HOST
193     2,      // ET_IPDOMAIN
194     2,      // ET_DNSDOMAIN
195     2,      // ET_NTDOMAIN
196     3,      // ET_OS
197     99,     // ET_UNKNOWN
198 };
199 
200 // Table with all fixed/predefined variables supported.
201 static FixedVariable aFixedVarTable[] =
202 {
203     { VARIABLE_INST,        PREDEFVAR_INST,         REPLACELENGTH_INST,     true                       },
204     { VARIABLE_PROG,        PREDEFVAR_PROG,         REPLACELENGTH_PROG,     true                       },
205     { VARIABLE_USER,        PREDEFVAR_USER,         REPLACELENGTH_USER,     true                       },
206     { VARIABLE_WORK,        PREDEFVAR_WORK,         REPLACELENGTH_WORK,     true                       },      // Special variable (transient)!
207     { VARIABLE_HOME,        PREDEFVAR_HOME,         REPLACELENGTH_HOME,     true                       },
208     { VARIABLE_TEMP,        PREDEFVAR_TEMP,         REPLACELENGTH_TEMP,     true                       },
209     { VARIABLE_PATH,        PREDEFVAR_PATH,         REPLACELENGTH_PATH,     true                       },
210     { VARIABLE_LANG,        PREDEFVAR_LANG,         REPLACELENGTH_LANG,     false                      },
211     { VARIABLE_LANGID,      PREDEFVAR_LANGID,       REPLACELENGTH_LANGID,   false                      },
212     { VARIABLE_VLANG,       PREDEFVAR_VLANG,        REPLACELENGTH_VLANG,    false                      },
213     { VARIABLE_INSTPATH,    PREDEFVAR_INSTPATH,     REPLACELENGTH_INSTPATH, true                       },
214     { VARIABLE_PROGPATH,    PREDEFVAR_PROGPATH,     REPLACELENGTH_PROGPATH, true                       },
215     { VARIABLE_USERPATH,    PREDEFVAR_USERPATH,     REPLACELENGTH_USERPATH, true                       },
216     { VARIABLE_INSTURL,     PREDEFVAR_INSTURL,      REPLACELENGTH_INSTURL,  true                       },
217     { VARIABLE_PROGURL,     PREDEFVAR_PROGURL,      REPLACELENGTH_PROGURL,  true                       },
218     { VARIABLE_USERURL,     PREDEFVAR_USERURL,      REPLACELENGTH_USERURL,  true                       },
219     { VARIABLE_WORKDIRURL,  PREDEFVAR_WORKDIRURL,   REPLACELENGTH_WORKDIRURL,true                      },  // Special variable (transient) and don't use for resubstitution!
220     // --> PB 2004-10-27 #i32656# - new variable of hierachy service
221     { VARIABLE_BASEINSTURL, PREDEFVAR_BASEINSTURL,  REPLACELENGTH_BASEINSTURL,true                     },
222     { VARIABLE_USERDATAURL, PREDEFVAR_USERDATAURL,  REPLACELENGTH_USERDATAURL,true                     },
223     // <--
224     { VARIABLE_BRANDBASEURL,PREDEFVAR_BRANDBASEURL, RTL_CONSTASCII_LENGTH(VARIABLE_BRANDBASEURL), true }
225 };
226 
227 //_________________________________________________________________________________________________________________
228 //      Implementation helper classes
229 //_________________________________________________________________________________________________________________
230 //
231 
232 OperatingSystem SubstitutePathVariables_Impl::GetOperatingSystemFromString( const rtl::OUString& aOSString )
233 {
234     for ( int i = 0; i < OS_COUNT; i++ )
235     {
236         if ( aOSString.equalsIgnoreAsciiCaseAsciiL( aOSTable[i].pOSString, aOSTable[i].nStrLen ))
237             return (OperatingSystem)i;
238     }
239 
240     return OS_UNKNOWN;
241 }
242 
243 EnvironmentType SubstitutePathVariables_Impl::GetEnvTypeFromString( const rtl::OUString& aEnvTypeString )
244 {
245     for ( int i = 0; i < ET_COUNT; i++ )
246     {
247         if ( aEnvTypeString.equalsIgnoreAsciiCaseAsciiL( aEnvTable[i].pOSString, aEnvTable[i].nStrLen ))
248             return (EnvironmentType)i;
249     }
250 
251     return ET_UNKNOWN;
252 }
253 
254 SubstitutePathVariables_Impl::SubstitutePathVariables_Impl( const Link& aNotifyLink ) :
255     utl::ConfigItem( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Office.Substitution" ))),
256     m_bYPDomainRetrieved( false ),
257     m_bDNSDomainRetrieved( false ),
258     m_bNTDomainRetrieved( false ),
259     m_bHostRetrieved( false ),
260     m_bOSRetrieved( false ),
261     m_aListenerNotify( aNotifyLink ),
262     m_aSharePointsNodeName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SharePoints" ))),
263     m_aDirPropertyName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/Directory" ))),
264     m_aEnvPropertyName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/Environment" ))),
265     m_aLevelSep( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" )))
266 {
267     // Enable notification mechanism
268     // We need it to get information about changes outside these class on our configuration branch
269     Sequence< rtl::OUString > aNotifySeq( 1 );
270     aNotifySeq[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SharePoints" ));
271     EnableNotification( aNotifySeq, sal_True );
272 }
273 
274 SubstitutePathVariables_Impl::~SubstitutePathVariables_Impl()
275 {
276 }
277 
278 void SubstitutePathVariables_Impl::GetSharePointsRules( SubstituteVariables& aSubstVarMap )
279 {
280     Sequence< rtl::OUString > aSharePointNames;
281     ReadSharePointsFromConfiguration( aSharePointNames );
282 
283     if ( aSharePointNames.getLength() > 0 )
284     {
285         sal_Int32 nSharePoints = 0;
286 
287         // Read SharePoints container from configuration
288         while ( nSharePoints < aSharePointNames.getLength() )
289         {
290             rtl::OUString aSharePointNodeName( m_aSharePointsNodeName );
291             aSharePointNodeName += rtl::OUString::createFromAscii( "/" );
292             aSharePointNodeName += aSharePointNames[ nSharePoints ];
293 
294             SubstituteRuleVector aRuleSet;
295             ReadSharePointRuleSetFromConfiguration( aSharePointNames[ nSharePoints ], aSharePointNodeName, aRuleSet );
296             if ( !aRuleSet.empty() )
297             {
298                 // We have at minimum one rule. Filter the correct rule out of the rule set
299                 // and put into our SubstituteVariable map
300                 SubstituteRule aActiveRule;
301                 if ( FilterRuleSet( aRuleSet, aActiveRule ))
302                 {
303                     // We have found an active rule
304                     aActiveRule.aSubstVariable = aSharePointNames[ nSharePoints ];
305                     aSubstVarMap.insert( SubstituteVariables::value_type(
306                     aActiveRule.aSubstVariable, aActiveRule ));
307                 }
308             }
309             ++nSharePoints;
310         }
311     }
312 }
313 
314 void SubstitutePathVariables_Impl::Notify( const com::sun::star::uno::Sequence< rtl::OUString >& /*aPropertyNames*/ )
315 {
316     // NOT implemented yet!
317 }
318 
319 void SubstitutePathVariables_Impl::Commit()
320 {
321 }
322 
323 
324 //_________________________________________________________________________________________________________________
325 //      private methods
326 //_________________________________________________________________________________________________________________
327 //
328 
329 OperatingSystem SubstitutePathVariables_Impl::GetOperatingSystem()
330 {
331     if ( !m_bOSRetrieved )
332     {
333 #ifdef SOLARIS
334         m_eOSType = OS_SOLARIS;
335 #elif defined LINUX
336         m_eOSType = OS_LINUX;
337 #elif defined WIN32
338         m_eOSType = OS_WINDOWS;
339 #elif defined UNIX
340         m_eOSType = OS_UNIX;
341 #else
342         m_eOSType = OS_UNKNOWN;
343 #endif
344         m_bOSRetrieved = sal_True;
345     }
346 
347     return m_eOSType;
348 }
349 
350 const rtl::OUString& SubstitutePathVariables_Impl::GetYPDomainName()
351 {
352     if ( !m_bYPDomainRetrieved )
353     {
354         m_aYPDomain = NetworkDomain::GetYPDomainName().toAsciiLowerCase();
355         m_bYPDomainRetrieved = sal_True;
356     }
357 
358     return m_aYPDomain;
359 }
360 
361 const rtl::OUString& SubstitutePathVariables_Impl::GetDNSDomainName()
362 {
363     if ( !m_bDNSDomainRetrieved )
364     {
365         rtl::OUString   aTemp;
366         osl::SocketAddr aSockAddr;
367         oslSocketResult aResult;
368 
369         rtl::OUString aHostName = GetHostName();
370         osl::SocketAddr::resolveHostname( aHostName, aSockAddr );
371         aTemp = aSockAddr.getHostname( &aResult );
372 
373         // DNS domain name begins after the first "."
374         sal_Int32 nIndex = aTemp.indexOf( '.' );
375         if ( nIndex >= 0 && aTemp.getLength() > nIndex+1 )
376             m_aDNSDomain = aTemp.copy( nIndex+1 ).toAsciiLowerCase();
377         else
378             m_aDNSDomain = rtl::OUString();
379 
380         m_bDNSDomainRetrieved = sal_True;
381     }
382 
383     return m_aDNSDomain;
384 }
385 
386 const rtl::OUString& SubstitutePathVariables_Impl::GetNTDomainName()
387 {
388     if ( !m_bNTDomainRetrieved )
389     {
390         m_aNTDomain = NetworkDomain::GetNTDomainName().toAsciiLowerCase();
391         m_bNTDomainRetrieved = sal_True;
392     }
393 
394     return m_aNTDomain;
395 }
396 
397 const rtl::OUString& SubstitutePathVariables_Impl::GetHostName()
398 {
399     if ( !m_bHostRetrieved )
400     {
401         rtl::OUString   aHostName;
402         oslSocketResult aSocketResult;
403 
404         m_aHost = osl::SocketAddr::getLocalHostname( &aSocketResult ).toAsciiLowerCase();
405     }
406 
407     return m_aHost;
408 }
409 
410 bool SubstitutePathVariables_Impl::FilterRuleSet( const SubstituteRuleVector& aRuleSet, SubstituteRule& aActiveRule )
411 {
412     bool bResult = sal_False;
413 
414     if ( !aRuleSet.empty() )
415     {
416         const sal_uInt32 nCount = aRuleSet.size();
417 
418         sal_Int16 nPrioCurrentRule = aEnvPrioTable[ ET_UNKNOWN ];
419         for ( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
420         {
421             const SubstituteRule& aRule = aRuleSet[nIndex];
422             EnvironmentType eEnvType        = aRule.aEnvType;
423 
424             // Check if environment type has a higher priority than current one!
425             if ( nPrioCurrentRule > aEnvPrioTable[eEnvType] )
426             {
427                 switch ( eEnvType )
428                 {
429                     case ET_HOST:
430                     {
431                         rtl::OUString aHost = GetHostName();
432                         rtl::OUString aHostStr;
433                         aRule.aEnvValue >>= aHostStr;
434                         aHostStr = aHostStr.toAsciiLowerCase();
435 
436                         // Pattern match if domain environment match
437                         WildCard aPattern(aHostStr);
438                         bool bMatch = aPattern.Matches(aHost);
439                         if ( bMatch )
440                         {
441                             aActiveRule      = aRule;
442                             bResult          = true;
443                             nPrioCurrentRule = aEnvPrioTable[eEnvType];
444                         }
445                     }
446                     break;
447 
448                     case ET_YPDOMAIN:
449                     case ET_DNSDOMAIN:
450                     case ET_NTDOMAIN:
451                     {
452                         rtl::OUString   aDomain;
453                         rtl::OUString   aDomainStr;
454                         aRule.aEnvValue >>= aDomainStr;
455                         aDomainStr = aDomainStr.toAsciiLowerCase();
456 
457                         // Retrieve the correct domain value
458                         if ( eEnvType == ET_YPDOMAIN )
459                             aDomain = GetYPDomainName();
460                         else if ( eEnvType == ET_DNSDOMAIN )
461                             aDomain = GetDNSDomainName();
462                         else
463                             aDomain = GetNTDomainName();
464 
465                         // Pattern match if domain environment match
466                         WildCard aPattern(aDomainStr);
467                         bool bMatch = aPattern.Matches(aDomain);
468                         if ( bMatch )
469                         {
470                             aActiveRule      = aRule;
471                             bResult          = true;
472                             nPrioCurrentRule = aEnvPrioTable[eEnvType];
473                         }
474                     }
475                     break;
476 
477                     case ET_OS:
478                     {
479                         // No pattern matching for OS type
480                         OperatingSystem eOSType = GetOperatingSystem();
481 
482                         sal_Int16 nValue = 0;
483                         aRule.aEnvValue >>= nValue;
484 
485                         bool            bUnix = ( eOSType == OS_LINUX ) || ( eOSType == OS_SOLARIS );
486                         OperatingSystem eRuleOSType = (OperatingSystem)nValue;
487 
488                         // Match if OS identical or rule is set to UNIX and OS is LINUX/SOLARIS!
489                         if (( eRuleOSType == eOSType ) || ( eRuleOSType == OS_UNIX && bUnix ))
490                         {
491                             aActiveRule      = aRule;
492                             bResult          = true;
493                             nPrioCurrentRule = aEnvPrioTable[eEnvType];
494                         }
495                     }
496                     break;
497 
498                     case ET_UNKNOWN: // nothing to do
499                         break;
500 
501                     default:
502                         break;
503                 }
504             }
505         }
506     }
507 
508     return bResult;
509 }
510 
511 void SubstitutePathVariables_Impl::ReadSharePointsFromConfiguration( Sequence< rtl::OUString >& aSharePointsSeq )
512 {
513     //returns all the names of all share point nodes
514     aSharePointsSeq = GetNodeNames( m_aSharePointsNodeName );
515 }
516 
517 void SubstitutePathVariables_Impl::ReadSharePointRuleSetFromConfiguration(
518         const rtl::OUString& aSharePointName,
519         const rtl::OUString& aSharePointNodeName,
520         SubstituteRuleVector& rRuleSet )
521 {
522     Sequence< rtl::OUString > aSharePointMappingsNodeNames = GetNodeNames( aSharePointNodeName, utl::CONFIG_NAME_LOCAL_PATH );
523 
524     sal_Int32 nSharePointMapping = 0;
525     while ( nSharePointMapping < aSharePointMappingsNodeNames.getLength() )
526     {
527         rtl::OUString aSharePointMapping( aSharePointNodeName );
528         aSharePointMapping += m_aLevelSep;
529         aSharePointMapping += aSharePointMappingsNodeNames[ nSharePointMapping ];
530 
531         // Read SharePointMapping
532         rtl::OUString aDirValue;
533         rtl::OUString aDirProperty( aSharePointMapping );
534         aDirProperty += m_aDirPropertyName;
535 
536         // Read only the directory property
537         Sequence< rtl::OUString > aDirPropertySeq( 1 );
538         aDirPropertySeq[0] = aDirProperty;
539 
540         Sequence< Any > aValueSeq = GetProperties( aDirPropertySeq );
541         if ( aValueSeq.getLength() == 1 )
542             aValueSeq[0] >>= aDirValue;
543 
544         // Read the environment setting
545         rtl::OUString aEnvUsed;
546         rtl::OUString aEnvProperty( aSharePointMapping );
547         aEnvProperty += m_aEnvPropertyName;
548         Sequence< rtl::OUString > aEnvironmentVariable = GetNodeNames( aEnvProperty );
549 
550         // Filter the property which has a value set
551         Sequence< rtl::OUString > aEnvUsedPropertySeq( aEnvironmentVariable.getLength() );
552 
553         rtl::OUString aEnvUsePropNameTemplate( aEnvProperty );
554         aEnvUsePropNameTemplate += m_aLevelSep;
555 
556         for ( sal_Int32 nProperty = 0; nProperty < aEnvironmentVariable.getLength(); nProperty++ )
557             aEnvUsedPropertySeq[nProperty] = rtl::OUString( aEnvUsePropNameTemplate + aEnvironmentVariable[nProperty] );
558 
559         Sequence< Any > aEnvUsedValueSeq;
560         aEnvUsedValueSeq = GetProperties( aEnvUsedPropertySeq );
561 
562         rtl::OUString aEnvUsedValue;
563         for ( sal_Int32 nIndex = 0; nIndex < aEnvironmentVariable.getLength(); nIndex++ )
564         {
565             if ( aEnvUsedValueSeq[nIndex] >>= aEnvUsedValue )
566             {
567                 aEnvUsed = aEnvironmentVariable[nIndex];
568                 break;
569             }
570         }
571 
572         // Decode the environment and optional the operatng system settings
573         Any                             aEnvValue;
574         EnvironmentType eEnvType = GetEnvTypeFromString( aEnvUsed );
575         if ( eEnvType == ET_OS )
576         {
577             OperatingSystem eOSType = GetOperatingSystemFromString( aEnvUsedValue );
578             aEnvValue <<= (sal_Int16)eOSType;
579         }
580         else
581             aEnvValue <<= aEnvUsedValue;
582 
583         // Create rule struct and push it into the rule set
584         SubstituteRule aRule( aSharePointName, aDirValue, aEnvValue, eEnvType );
585         rRuleSet.push_back( aRule );
586 
587         ++nSharePointMapping;
588     }
589 }
590 
591 //*****************************************************************************************************************
592 //      XInterface, XTypeProvider, XServiceInfo
593 //*****************************************************************************************************************
594 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE  ( SubstitutePathVariables                     ,
595                                           ::cppu::OWeakObject                         ,
596                                           SERVICENAME_SUBSTITUTEPATHVARIABLES         ,
597                                           IMPLEMENTATIONNAME_SUBSTITUTEPATHVARIABLES    )
598 
599 DEFINE_INIT_SERVICE                     (   SubstitutePathVariables, {} )
600 
601 
602 SubstitutePathVariables::SubstitutePathVariables( const Reference< XMultiServiceFactory >& xServiceManager ) :
603     ThreadHelpBase(),
604     m_aVarStart( SIGN_STARTVARIABLE ),
605     m_aVarEnd( SIGN_ENDVARIABLE ),
606     m_aImpl( LINK( this, SubstitutePathVariables, implts_ConfigurationNotify )),
607     m_xServiceManager( xServiceManager )
608 {
609     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::SubstitutePathVariables" );
610     int i;
611 
612     SetPredefinedPathVariables( m_aPreDefVars );
613     m_aImpl.GetSharePointsRules( m_aSubstVarMap );
614 
615     // Init the predefined/fixed variable to index hash map
616     for ( i = 0; i < PREDEFVAR_COUNT; i++ )
617     {
618         // Store variable name into struct of predefined/fixed variables
619         m_aPreDefVars.m_FixedVarNames[i] = rtl::OUString::createFromAscii( aFixedVarTable[i].pVarName );
620 
621         // Create hash map entry
622         m_aPreDefVarMap.insert( VarNameToIndexMap::value_type(
623             m_aPreDefVars.m_FixedVarNames[i], aFixedVarTable[i].nEnumValue ) );
624     }
625 
626     // Sort predefined/fixed variable to path length
627     for ( i = 0; i < PREDEFVAR_COUNT; i++ )
628     {
629         if (( i != PREDEFVAR_WORKDIRURL ) && ( i != PREDEFVAR_PATH ))
630         {
631             // Special path variables, don't include into automatic resubstituion search!
632             // $(workdirurl) is not allowed to resubstitute! This variable is the value of path settings entry
633             // and it could be possible that it will be resubstituted by itself!!
634             // Example: WORK_PATH=c:\test, $(workdirurl)=WORK_PATH => WORK_PATH=$(workdirurl) and this cannot be substituted!
635             ReSubstFixedVarOrder aFixedVar;
636             aFixedVar.eVariable       = aFixedVarTable[i].nEnumValue;
637             aFixedVar.nVarValueLength = m_aPreDefVars.m_FixedVar[(sal_Int32)aFixedVar.eVariable].getLength();
638             m_aReSubstFixedVarOrder.push_back( aFixedVar );
639         }
640     }
641     m_aReSubstFixedVarOrder.sort();
642 
643     // Sort user variables to path length
644     SubstituteVariables::const_iterator pIter;
645     for ( pIter = m_aSubstVarMap.begin(); pIter != m_aSubstVarMap.end(); pIter++ )
646     {
647         ReSubstUserVarOrder aUserOrderVar;
648         rtl::OUStringBuffer aStrBuffer( pIter->second.aSubstVariable.getLength() );
649         aStrBuffer.append( m_aVarStart );
650         aStrBuffer.append( pIter->second.aSubstVariable );
651         aStrBuffer.append( m_aVarEnd );
652         aUserOrderVar.aVarName        = aStrBuffer.makeStringAndClear();
653         aUserOrderVar.nVarValueLength = pIter->second.aSubstVariable.getLength();
654         m_aReSubstUserVarOrder.push_back( aUserOrderVar );
655     }
656     m_aReSubstUserVarOrder.sort();
657 }
658 
659 SubstitutePathVariables::~SubstitutePathVariables()
660 {
661 }
662 
663 // XStringSubstitution
664 rtl::OUString SAL_CALL SubstitutePathVariables::substituteVariables( const ::rtl::OUString& aText, sal_Bool bSubstRequired )
665 throw ( NoSuchElementException, RuntimeException )
666 {
667     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::substituteVariables" );
668     ResetableGuard aLock( m_aLock );
669     return impl_substituteVariable( aText, bSubstRequired );
670 }
671 
672 rtl::OUString SAL_CALL SubstitutePathVariables::reSubstituteVariables( const ::rtl::OUString& aText )
673 throw ( RuntimeException )
674 {
675     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::reSubstituteVariables" );
676     ResetableGuard aLock( m_aLock );
677     return impl_reSubstituteVariables( aText );
678 }
679 
680 rtl::OUString SAL_CALL SubstitutePathVariables::getSubstituteVariableValue( const ::rtl::OUString& aVariable )
681 throw ( NoSuchElementException, RuntimeException )
682 {
683     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::getSubstituteVariableValue" );
684     ResetableGuard aLock( m_aLock );
685     return impl_getSubstituteVariableValue( aVariable );
686 }
687 
688 //_________________________________________________________________________________________________________________
689 //      protected methods
690 //_________________________________________________________________________________________________________________
691 //
692 
693 IMPL_LINK( SubstitutePathVariables, implts_ConfigurationNotify, SubstitutePathNotify*, EMPTYARG )
694 {
695     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
696     ResetableGuard aLock( m_aLock );
697 
698     return 0;
699 }
700 
701 rtl::OUString SubstitutePathVariables::ConvertOSLtoUCBURL( const rtl::OUString& aOSLCompliantURL ) const
702 {
703     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::ConvertOSLtoUCBURL" );
704     String                  aResult;
705     rtl::OUString   aTemp;
706 
707     osl::FileBase::getSystemPathFromFileURL( aOSLCompliantURL, aTemp );
708     utl::LocalFileHelper::ConvertPhysicalNameToURL( aTemp, aResult );
709 
710     // Not all OSL URL's can be mapped to UCB URL's!
711     if ( aResult.Len() == 0 )
712         return aOSLCompliantURL;
713     else
714         return rtl::OUString( aResult );
715 }
716 
717 rtl::OUString SubstitutePathVariables::GetWorkPath() const
718 {
719     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::GetWorkPath" );
720         rtl::OUString aWorkPath;
721     ::comphelper::ConfigurationHelper::readDirectKey(
722                             m_xServiceManager,
723                             ::rtl::OUString::createFromAscii("org.openoffice.Office.Paths"),
724                             ::rtl::OUString::createFromAscii("Paths/Work"),
725                             ::rtl::OUString::createFromAscii("WritePath"),
726                             ::comphelper::ConfigurationHelper::E_READONLY) >>= aWorkPath;
727     return aWorkPath;
728 }
729 
730 rtl::OUString SubstitutePathVariables::GetWorkVariableValue() const
731 {
732     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::GetWorkVariableValue" );
733     ::rtl::OUString aWorkPath;
734     ::comphelper::ConfigurationHelper::readDirectKey(
735                             m_xServiceManager,
736                             ::rtl::OUString::createFromAscii("org.openoffice.Office.Paths"),
737                             ::rtl::OUString::createFromAscii("Variables"),
738                             ::rtl::OUString::createFromAscii("Work"),
739                             ::comphelper::ConfigurationHelper::E_READONLY) >>= aWorkPath;
740 
741     // fallback to $HOME in case platform dependend config layer does not return
742     // an usuable work dir value.
743     if (aWorkPath.getLength() < 1)
744     {
745         osl::Security aSecurity;
746         aSecurity.getHomeDir( aWorkPath );
747     }
748     return ConvertOSLtoUCBURL( aWorkPath );
749 }
750 
751 rtl::OUString SubstitutePathVariables::GetHomeVariableValue() const
752 {
753     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::GetHomeVariableValue" );
754     osl::Security   aSecurity;
755     rtl::OUString   aHomePath;
756 
757     aSecurity.getHomeDir( aHomePath );
758     return ConvertOSLtoUCBURL( aHomePath );
759 }
760 
761 rtl::OUString SubstitutePathVariables::GetPathVariableValue() const
762 {
763     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::GetPathVariableValue" );
764     const int PATH_EXTEND_FACTOR = 120;
765 
766     rtl::OUString aRetStr;
767     const char*   pEnv = getenv( "PATH" );
768 
769     if ( pEnv )
770     {
771         rtl::OUString       aTmp;
772         rtl::OUString       aPathList( pEnv, strlen( pEnv ), gsl_getSystemTextEncoding() );
773         rtl::OUStringBuffer aPathStrBuffer( aPathList.getLength() * PATH_EXTEND_FACTOR / 100 );
774 
775         bool      bAppendSep = false;
776         sal_Int32 nToken = 0;
777         do
778         {
779             ::rtl::OUString sToken = aPathList.getToken(0, SAL_PATHSEPARATOR, nToken);
780             if (sToken.getLength())
781             {
782                 osl::FileBase::getFileURLFromSystemPath( sToken, aTmp );
783                 if ( bAppendSep )
784                     aPathStrBuffer.appendAscii( ";" ); // Office uses ';' as path separator
785                 aPathStrBuffer.append( aTmp );
786                 bAppendSep = true;
787             }
788         }
789         while(nToken>=0);
790 
791         aRetStr = aPathStrBuffer.makeStringAndClear();
792     }
793 
794     return aRetStr;
795 }
796 
797 rtl::OUString SubstitutePathVariables::impl_substituteVariable( const ::rtl::OUString& rText, bool bSubstRequired )
798 throw ( NoSuchElementException, RuntimeException )
799 {
800     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::impl_substituteVariable" );
801     // This is maximal recursive depth supported!
802     const sal_Int32 nMaxRecursiveDepth = 8;
803 
804     rtl::OUString   aWorkText = rText;
805     rtl::OUString   aResult;
806 
807     // Use vector with strings to detect endless recursions!
808     std::vector< rtl::OUString > aEndlessRecursiveDetector;
809 
810     // Search for first occure of "$(...".
811     sal_Int32   nDepth = 0;
812     sal_Int32   bSubstitutionCompleted = sal_False;
813     sal_Int32   nPosition       = aWorkText.indexOf( m_aVarStart );     // = first position of "$(" in string
814     sal_Int32   nLength = 0; // = count of letters from "$(" to ")" in string
815     bool        bVarNotSubstituted = false;
816 
817     // Have we found any variable like "$(...)"?
818     if ( nPosition != STRPOS_NOTFOUND )
819     {
820         // Yes; Get length of found variable.
821         // If no ")" was found - nLength is set to 0 by default! see before.
822         sal_Int32 nEndPosition = aWorkText.indexOf( m_aVarEnd, nPosition );
823         if ( nEndPosition != STRPOS_NOTFOUND )
824             nLength = nEndPosition - nPosition + 1;
825     }
826 
827     // Is there something to replace ?
828     bool bWorkRetrieved       = false;
829     bool bWorkDirURLRetrieved = false;
830     while ( !bSubstitutionCompleted && nDepth < nMaxRecursiveDepth )
831     {
832         while ( ( nPosition != STRPOS_NOTFOUND ) && ( nLength > 3 ) ) // "$(" ")"
833         {
834             // YES; Get the next variable for replace.
835             sal_Int32     nReplaceLength  = 0;
836             rtl::OUString aReplacement;
837             rtl::OUString aSubString      = aWorkText.copy( nPosition, nLength );
838             rtl::OUString aSubVarString;
839 
840             // Path variables are not case sensitive!
841             aSubVarString = aSubString.toAsciiLowerCase();
842             VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( aSubVarString );
843             if ( pNTOIIter != m_aPreDefVarMap.end() )
844             {
845                 // Fixed/Predefined variable found
846                 PreDefVariable nIndex = (PreDefVariable)pNTOIIter->second;
847 
848                 // Determine variable value and length from array/table
849                 if ( nIndex == PREDEFVAR_WORK && !bWorkRetrieved )
850                 {
851                     // Transient value, retrieve it again
852                     m_aPreDefVars.m_FixedVar[ (PreDefVariable)nIndex ] = GetWorkVariableValue();
853                     bWorkRetrieved = true;
854                 }
855                 else if ( nIndex == PREDEFVAR_WORKDIRURL && !bWorkDirURLRetrieved )
856                 {
857                     // Transient value, retrieve it again
858                     m_aPreDefVars.m_FixedVar[ (PreDefVariable)nIndex ] = GetWorkPath();
859                     bWorkDirURLRetrieved = true;
860                 }
861 
862                 // Check preconditions to substitue path variables.
863                 // 1. A path variable can only be substituted if it follows a SEARCHPATH_DELIMITER ';'!
864                 // 2. It's located exactly at the start of the string being substituted!
865                 if (( aFixedVarTable[ int( nIndex ) ].bAbsPath && (( nPosition == 0 ) || (( nPosition > 0 ) && ( aWorkText[nPosition-1] == ';')))) ||
866 		    ( !aFixedVarTable[ int( nIndex ) ].bAbsPath ))
867 		{
868                     aReplacement = m_aPreDefVars.m_FixedVar[ (PreDefVariable)nIndex ];
869                     nReplaceLength = nLength;
870                 }
871             }
872             else
873             {
874                 // Extract the variable name and try to find in the user defined variable set
875                 rtl::OUString aVarName = aSubString.copy( 2, nLength-3 );
876                 SubstituteVariables::const_iterator pIter = m_aSubstVarMap.find( aVarName );
877                 if ( pIter != m_aSubstVarMap.end() )
878                 {
879                     // Found.
880                     aReplacement = pIter->second.aSubstValue;
881                     nReplaceLength = nLength;
882                 }
883             }
884 
885             // Have we found something to replace?
886             if ( nReplaceLength > 0 )
887             {
888                 // Yes ... then do it.
889                 aWorkText = aWorkText.replaceAt( nPosition, nReplaceLength, aReplacement );
890             }
891             else
892             {
893                 // Variable not known
894                 bVarNotSubstituted = false;
895                 nPosition += nLength;
896             }
897 
898             // Step after replaced text! If no text was replaced (unknown variable!),
899             // length of aReplacement is 0 ... and we don't step then.
900             nPosition += aReplacement.getLength();
901 
902             // We must control index in string before call something at OUString!
903             // The OUString-implementation don't do it for us :-( but the result is not defined otherwise.
904             if ( nPosition + 1 > aWorkText.getLength() )
905             {
906                 // Position is out of range. Break loop!
907                 nPosition = STRPOS_NOTFOUND;
908                 nLength = 0;
909             }
910             else
911             {
912                 // Else; Position is valid. Search for next variable to replace.
913                 nPosition = aWorkText.indexOf( m_aVarStart, nPosition );
914                 // Have we found any variable like "$(...)"?
915                 if ( nPosition != STRPOS_NOTFOUND )
916                 {
917                     // Yes; Get length of found variable. If no ")" was found - nLength must set to 0!
918                     nLength = 0;
919                     sal_Int32 nEndPosition = aWorkText.indexOf( m_aVarEnd, nPosition );
920                     if ( nEndPosition != STRPOS_NOTFOUND )
921                         nLength = nEndPosition - nPosition + 1;
922                 }
923             }
924         }
925 
926         nPosition = aWorkText.indexOf( m_aVarStart );
927         if ( nPosition == -1 )
928         {
929             bSubstitutionCompleted = sal_True;
930             break; // All variables are substituted
931         }
932         else
933         {
934             // Check for recursion
935             const sal_uInt32 nCount = aEndlessRecursiveDetector.size();
936             for ( sal_uInt32 i=0; i < nCount; i++ )
937             {
938                 if ( aEndlessRecursiveDetector[i] == aWorkText )
939                 {
940                     if ( bVarNotSubstituted )
941                         break; // Not all variables could be substituted!
942                     else
943                     {
944                         nDepth = nMaxRecursiveDepth;
945                         break; // Recursion detected!
946                     }
947                 }
948             }
949 
950             aEndlessRecursiveDetector.push_back( aWorkText );
951 
952             // Initialize values for next
953             sal_Int32 nEndPosition = aWorkText.indexOf( m_aVarEnd, nPosition );
954             if ( nEndPosition != STRPOS_NOTFOUND )
955                 nLength = nEndPosition - nPosition + 1;
956             bVarNotSubstituted = sal_False;
957             ++nDepth;
958         }
959     }
960 
961     // Fill return value with result
962     if ( bSubstitutionCompleted )
963     {
964         // Substitution successfull!
965         aResult = aWorkText;
966     }
967     else
968     {
969         // Substitution not successfull!
970         if ( nDepth == nMaxRecursiveDepth )
971         {
972             // recursion depth reached!
973             if ( bSubstRequired )
974             {
975                 rtl::OUString aMsg( RTL_CONSTASCII_USTRINGPARAM( "Endless recursion detected. Cannot substitute variables!" ));
976                 throw NoSuchElementException( aMsg, (cppu::OWeakObject *)this );
977             }
978             else
979                 aResult = rText;
980         }
981         else
982         {
983             // variable in text but unknwon!
984             if ( bSubstRequired )
985             {
986                 rtl::OUString aMsg( RTL_CONSTASCII_USTRINGPARAM( "Unknown variable found!" ));
987                 throw NoSuchElementException( aMsg, (cppu::OWeakObject *)this );
988             }
989             else
990                 aResult = aWorkText;
991         }
992     }
993 
994     return aResult;
995 }
996 
997 rtl::OUString SubstitutePathVariables::impl_reSubstituteVariables( const ::rtl::OUString& rURL )
998 throw ( RuntimeException )
999 {
1000     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::impl_reSubstituteVariables" );
1001     rtl::OUString aURL;
1002 
1003     INetURLObject aUrl( rURL );
1004     if ( !aUrl.HasError() )
1005         aURL = aUrl.GetMainURL( INetURLObject::NO_DECODE );
1006     else
1007     {
1008         // Convert a system path to a UCB compliant URL before resubstitution
1009         rtl::OUString aTemp;
1010         if ( osl::FileBase::getFileURLFromSystemPath( rURL, aTemp ) == osl::FileBase::E_None )
1011         {
1012             aTemp = ConvertOSLtoUCBURL( aTemp );
1013             if ( aTemp.getLength() )
1014                 aURL = INetURLObject( aTemp ).GetMainURL( INetURLObject::NO_DECODE );
1015             else
1016                 return rURL;
1017         }
1018         else
1019         {
1020             // rURL is not a valid URL nor a osl system path. Give up and return error!
1021             return rURL;
1022         }
1023     }
1024 
1025     // Due to a recursive definition this code must exchange variables with variables!
1026     bool bResubstitutionCompleted = false;
1027     bool bVariableFound           = false;
1028 
1029     // Get transient predefined path variable $(work) value before starting resubstitution
1030     m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
1031 
1032     while ( !bResubstitutionCompleted )
1033     {
1034         ReSubstFixedVarOrderVector::const_iterator pIterFixed;
1035         for ( pIterFixed = m_aReSubstFixedVarOrder.begin(); pIterFixed != m_aReSubstFixedVarOrder.end(); pIterFixed++ )
1036         {
1037             rtl::OUString aValue = m_aPreDefVars.m_FixedVar[ (sal_Int32)pIterFixed->eVariable ];
1038             sal_Int32 nPos = aURL.indexOf( aValue );
1039             if ( nPos >= 0 )
1040             {
1041                 bool bMatch = true;
1042                 if ( pIterFixed->eVariable == PREDEFVAR_LANG ||
1043                      pIterFixed->eVariable == PREDEFVAR_LANGID ||
1044                      pIterFixed->eVariable == PREDEFVAR_VLANG )
1045                 {
1046                     // Special path variables as they can occur in the middle of a path. Only match if they
1047                     // describe a whole directory and not only a substring of a directory!
1048                     const sal_Unicode* pStr = aURL.getStr();
1049 
1050                     if ( nPos > 0 )
1051                         bMatch = ( aURL[ nPos-1 ] == '/' );
1052 
1053                     if ( bMatch )
1054                     {
1055                         if ( nPos + aValue.getLength() < aURL.getLength() )
1056                             bMatch = ( pStr[ nPos + aValue.getLength() ] == '/' );
1057                     }
1058                 }
1059 
1060                 if ( bMatch )
1061                 {
1062                     rtl::OUStringBuffer aStrBuffer( aURL.getLength() );
1063                     aStrBuffer.append( aURL.copy( 0, nPos ) );
1064                     aStrBuffer.append( m_aPreDefVars.m_FixedVarNames[ (sal_Int32)pIterFixed->eVariable ] ); // Get the variable name for struct var name array!
1065                     aStrBuffer.append( aURL.copy( nPos + aValue.getLength(), ( aURL.getLength() - ( nPos + aValue.getLength() )) ));
1066                     aURL = aStrBuffer.makeStringAndClear();
1067                     bVariableFound = true; // Resubstitution not finished yet!
1068                     break;
1069                 }
1070             }
1071         }
1072 
1073         // This part can be iteratered more than one time as variables can contain variables again!
1074         ReSubstUserVarOrderVector::const_iterator pIterUser;
1075         for ( pIterUser = m_aReSubstUserVarOrder.begin(); pIterUser != m_aReSubstUserVarOrder.end(); pIterUser++ )
1076         {
1077             rtl::OUString aVarValue = pIterUser->aVarName;
1078             sal_Int32 nPos = aURL.indexOf( aVarValue );
1079             if ( nPos >= 0 )
1080             {
1081                 rtl::OUStringBuffer aStrBuffer( aURL.getLength() );
1082                 aStrBuffer.append( aURL.copy( 0, nPos ) );
1083                 aStrBuffer.append( m_aVarStart );
1084                 aStrBuffer.append( aVarValue );
1085                 aStrBuffer.append( m_aVarEnd );
1086                 aStrBuffer.append( aURL.copy( nPos +  aVarValue.getLength(), ( aURL.getLength() - ( nPos + aVarValue.getLength() )) ));
1087                 aURL = aStrBuffer.makeStringAndClear();
1088                 bVariableFound = true;  // Resubstitution not finished yet!
1089             }
1090         }
1091 
1092         if ( !bVariableFound )
1093             bResubstitutionCompleted = true;
1094         else
1095             bVariableFound = sal_False; // Next resubstitution
1096     }
1097 
1098     return aURL;
1099 }
1100 
1101 // This method support both request schemes "$("<varname>")" or "<varname>".
1102 ::rtl::OUString SubstitutePathVariables::impl_getSubstituteVariableValue( const ::rtl::OUString& rVariable )
1103 throw ( NoSuchElementException, RuntimeException )
1104 {
1105     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::impl_getSubstituteVariableValue" );
1106     rtl::OUString aVariable;
1107 
1108     sal_Int32 nPos = rVariable.indexOf( m_aVarStart );
1109     if ( nPos == -1 )
1110     {
1111         // Prepare variable name before hash map access
1112         rtl::OUStringBuffer aStrBuffer( rVariable.getLength() + m_aVarStart.getLength() + m_aVarEnd.getLength() );
1113         aStrBuffer.append( m_aVarStart );
1114         aStrBuffer.append( rVariable );
1115         aStrBuffer.append( m_aVarEnd );
1116         aVariable = aStrBuffer.makeStringAndClear();
1117     }
1118 
1119     VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( ( nPos == -1 ) ? aVariable : rVariable );
1120 
1121     // Fixed/Predefined variable
1122     if ( pNTOIIter != m_aPreDefVarMap.end() )
1123     {
1124         PreDefVariable nIndex = (PreDefVariable)pNTOIIter->second;
1125         return m_aPreDefVars.m_FixedVar[(sal_Int32)nIndex];
1126     }
1127     else
1128     {
1129         // Prepare variable name before hash map access
1130         if ( nPos >= 0 )
1131         {
1132             if ( rVariable.getLength() > 3 )
1133                 aVariable = rVariable.copy( 2, rVariable.getLength() - 3 );
1134             else
1135             {
1136                 rtl::OUString aExceptionText( RTL_CONSTASCII_USTRINGPARAM( "Unknown variable!" ));
1137                 throw NoSuchElementException();
1138             }
1139         }
1140         else
1141             aVariable = rVariable;
1142 
1143         // User defined variable
1144         SubstituteVariables::const_iterator pIter = m_aSubstVarMap.find( aVariable );
1145         if ( pIter != m_aSubstVarMap.end() )
1146         {
1147             // found!
1148             return pIter->second.aSubstValue;
1149         }
1150 
1151         rtl::OUString aExceptionText( RTL_CONSTASCII_USTRINGPARAM( "Unknown variable!" ));
1152         throw NoSuchElementException( aExceptionText, (cppu::OWeakObject *)this );
1153     }
1154 }
1155 
1156 void SubstitutePathVariables::SetPredefinedPathVariables( PredefinedPathVariables& aPreDefPathVariables )
1157 {
1158     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "SubstitutePathVariables::SetPredefinedPathVariables" );
1159     Any             aAny;
1160     ::rtl::OUString aOfficePath;
1161     ::rtl::OUString aUserPath;
1162     ::rtl::OUString aTmp;
1163     ::rtl::OUString aTmp2;
1164     String          aResult;
1165 
1166     // Get inspath and userpath from bootstrap mechanism in every case as file URL
1167     ::utl::Bootstrap::PathStatus aState;
1168     ::rtl::OUString              sVal  ;
1169 
1170     aState = utl::Bootstrap::locateBaseInstallation( sVal );
1171     if( aState==::utl::Bootstrap::PATH_EXISTS ) {
1172         aPreDefPathVariables.m_FixedVar[ PREDEFVAR_INSTPATH ] = ConvertOSLtoUCBURL( sVal );
1173     }
1174     else {
1175         LOG_ERROR( "SubstitutePathVariables::SetPredefinedPathVariables", "Bootstrap code has no value for instpath!");
1176     }
1177 
1178     aState = utl::Bootstrap::locateUserData( sVal );
1179     //There can be the valid case that there is no user installation. For example, "unopkg sync"
1180     //is currently (OOo3.4) run as part of the setup. Then no user installation is required.
1181     //Therefore we do not assert here.
1182     if( aState == ::utl::Bootstrap::PATH_EXISTS ) {
1183         aPreDefPathVariables.m_FixedVar[ PREDEFVAR_USERPATH ] = ConvertOSLtoUCBURL( sVal );
1184     }
1185 
1186     // Set $(inst), $(instpath), $(insturl)
1187     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_INSTURL ]    = aPreDefPathVariables.m_FixedVar[ PREDEFVAR_INSTPATH ];
1188     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_INST ]       = aPreDefPathVariables.m_FixedVar[ PREDEFVAR_INSTPATH ];
1189     // --> PB 2004-10-27 #i32656# - new variable of hierachy service
1190     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_BASEINSTURL ]= aPreDefPathVariables.m_FixedVar[ PREDEFVAR_INSTPATH ];
1191     // <--
1192 
1193     // Set $(user), $(userpath), $(userurl)
1194     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_USERURL ]    = aPreDefPathVariables.m_FixedVar[ PREDEFVAR_USERPATH ];
1195     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_USER ]       = aPreDefPathVariables.m_FixedVar[ PREDEFVAR_USERPATH ];
1196     // --> PB 2004-11-11 #i32656# - new variable of hierachy service
1197     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_USERDATAURL ]= aPreDefPathVariables.m_FixedVar[ PREDEFVAR_USERPATH ];
1198     // <--
1199 
1200     // Detect the program directory
1201     // Set $(prog), $(progpath), $(progurl)
1202     INetURLObject aProgObj(
1203     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_INSTPATH ] );
1204     if ( !aProgObj.HasError() && aProgObj.insertName( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("program")) ) )
1205     {
1206         aPreDefPathVariables.m_FixedVar[ PREDEFVAR_PROGPATH ] = aProgObj.GetMainURL(INetURLObject::NO_DECODE);
1207         aPreDefPathVariables.m_FixedVar[ PREDEFVAR_PROGURL ]  = aPreDefPathVariables.m_FixedVar[ PREDEFVAR_PROGPATH ];
1208         aPreDefPathVariables.m_FixedVar[ PREDEFVAR_PROG ]     = aPreDefPathVariables.m_FixedVar[ PREDEFVAR_PROGPATH ];
1209     }
1210 
1211     // Detect the language type of the current office
1212     aPreDefPathVariables.m_eLanguageType = LANGUAGE_ENGLISH_US;
1213     rtl::OUString aLocaleStr;
1214     if ( utl::ConfigManager::GetConfigManager()->GetDirectConfigProperty( utl::ConfigManager::LOCALE ) >>= aLocaleStr )
1215         aPreDefPathVariables.m_eLanguageType = MsLangId::convertIsoStringToLanguage( aLocaleStr );
1216     else
1217     {
1218         LOG_ERROR( "SubstitutePathVariables::SetPredefinedPathVariables", "Wrong Any type for language!" );
1219     }
1220 
1221     // Set $(lang)
1222     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_LANG ] = ConvertOSLtoUCBURL(
1223     rtl::OUString::createFromAscii( ResMgr::GetLang( aPreDefPathVariables.m_eLanguageType, 0 ) ));
1224 
1225     // Set $(vlang)
1226     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_VLANG ] = aLocaleStr;
1227 
1228     // Set $(langid)
1229     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_LANGID ] = rtl::OUString::valueOf( (sal_Int32)aPreDefPathVariables.m_eLanguageType );
1230 
1231     // Set the other pre defined path variables
1232     // Set $(work)
1233     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
1234     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_HOME ] = GetHomeVariableValue();
1235 
1236     // Set $(workdirurl) this is the value of the path PATH_WORK which doesn't make sense
1237     // anymore because the path settings service has this value! It can deliver this value more
1238     // quickly than the substitution service!
1239     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_WORKDIRURL ] = GetWorkPath();
1240 
1241     // Set $(path) variable
1242     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_PATH ] = GetPathVariableValue();
1243 
1244     // Set $(temp)
1245     osl::FileBase::getTempDirURL( aTmp );
1246     aPreDefPathVariables.m_FixedVar[ PREDEFVAR_TEMP ] = ConvertOSLtoUCBURL( aTmp );
1247 
1248     aPreDefPathVariables.m_FixedVar[PREDEFVAR_BRANDBASEURL] = rtl::OUString(
1249     RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR"));
1250     rtl::Bootstrap::expandMacros(
1251         aPreDefPathVariables.m_FixedVar[PREDEFVAR_BRANDBASEURL]);
1252 }
1253 
1254 } // namespace framework
1255