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