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_ucbhelper.hxx"
26 
27 /**************************************************************************
28                                 TODO
29  **************************************************************************
30 
31  *************************************************************************/
32 
33 #include <utility>
34 #include <vector>
35 #include <list>
36 #include <osl/mutex.hxx>
37 #include <rtl/ref.hxx>
38 #include <osl/socket.hxx>
39 #include <rtl/ustrbuf.hxx>
40 #include <com/sun/star/container/XNameAccess.hpp>
41 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
42 #include <com/sun/star/util/XChangesListener.hpp>
43 #include <com/sun/star/util/XChangesNotifier.hpp>
44 #include <cppuhelper/implbase1.hxx>
45 #include "ucbhelper/proxydecider.hxx"
46 
47 using namespace com::sun::star;
48 using namespace ucbhelper;
49 
50 #define CONFIG_ROOT_KEY      "org.openoffice.Inet/Settings"
51 #define PROXY_TYPE_KEY       "ooInetProxyType"
52 #define NO_PROXY_LIST_KEY    "ooInetNoProxy"
53 #define HTTP_PROXY_NAME_KEY  "ooInetHTTPProxyName"
54 #define HTTP_PROXY_PORT_KEY  "ooInetHTTPProxyPort"
55 #define HTTPS_PROXY_NAME_KEY "ooInetHTTPSProxyName"
56 #define HTTPS_PROXY_PORT_KEY "ooInetHTTPSProxyPort"
57 #define FTP_PROXY_NAME_KEY   "ooInetFTPProxyName"
58 #define FTP_PROXY_PORT_KEY   "ooInetFTPProxyPort"
59 
60 //=========================================================================
61 namespace ucbhelper
62 {
63 
64 //=========================================================================
65 namespace proxydecider_impl
66 {
67 
68 // A simple case ignoring wildcard matcher.
69 class WildCard
70 {
71 private:
72     rtl::OString m_aWildString;
73 
74 public:
WildCard(const rtl::OUString & rWildCard)75     WildCard( const rtl::OUString& rWildCard )
76     : m_aWildString(
77         rtl::OUStringToOString(
78             rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
79 
80     bool Matches( const rtl::OUString & rStr ) const;
81 };
82 
83 //=========================================================================
84 typedef std::pair< WildCard, WildCard > NoProxyListEntry;
85 
86 //=========================================================================
87 
88 class HostnameCache
89 {
90     typedef std::pair< rtl::OUString, rtl::OUString > HostListEntry;
91 
92     std::list< HostListEntry >     m_aHostList;
93     sal_uInt32                     m_nCapacity;
94 
95 public:
HostnameCache(sal_uInt32 nCapacity)96     explicit HostnameCache( sal_uInt32 nCapacity )
97         : m_nCapacity( nCapacity ) {}
98 
get(const rtl::OUString & rKey,rtl::OUString & rValue) const99     bool get( const rtl::OUString & rKey, rtl::OUString & rValue ) const
100     {
101         std::list< HostListEntry >::const_iterator it
102             = m_aHostList.begin();
103         const std::list< HostListEntry >::const_iterator end
104             = m_aHostList.end();
105 
106         while ( it != end )
107         {
108             if ( (*it).first == rKey )
109             {
110                 rValue = (*it).second;
111                 return true;
112             }
113             it++;
114         }
115         return false;
116     }
117 
put(const rtl::OUString & rKey,const rtl::OUString & rValue)118     void put( const rtl::OUString & rKey, const rtl::OUString & rValue )
119     {
120         if ( m_aHostList.size() == m_nCapacity )
121             m_aHostList.resize( m_nCapacity / 2 );
122 
123         m_aHostList.push_front( HostListEntry( rKey, rValue ) );
124     }
125 };
126 
127 //=========================================================================
128 class InternetProxyDecider_Impl :
129     public cppu::WeakImplHelper1< util::XChangesListener >
130 {
131     mutable osl::Mutex                       m_aMutex;
132     InternetProxyServer                      m_aHttpProxy;
133     InternetProxyServer                      m_aHttpsProxy;
134     InternetProxyServer                      m_aFtpProxy;
135     const InternetProxyServer                m_aEmptyProxy;
136     sal_Int32                                m_nProxyType;
137     uno::Reference< util::XChangesNotifier > m_xNotifier;
138     std::vector< NoProxyListEntry >          m_aNoProxyList;
139     mutable HostnameCache                    m_aHostnames;
140 
141 private:
142     bool shouldUseProxy( const rtl::OUString & rHost,
143                          sal_Int32 nPort,
144                          bool bUseFullyQualified ) const;
145 public:
146     InternetProxyDecider_Impl(
147         const uno::Reference< lang::XMultiServiceFactory >& rxSMgr );
148     virtual ~InternetProxyDecider_Impl();
149 
150     static rtl::Reference< InternetProxyDecider_Impl > createInstance(
151         const uno::Reference< lang::XMultiServiceFactory >& rxSMgr );
152 
153     void dispose();
154 
155     const InternetProxyServer & getProxy( const rtl::OUString & rProtocol,
156                                           const rtl::OUString & rHost,
157                                           sal_Int32 nPort ) const;
158 
159     // XChangesListener
160     virtual void SAL_CALL changesOccurred( const util::ChangesEvent& Event )
161         throw( uno::RuntimeException );
162 
163     // XEventListener ( base of XChangesLisetenr )
164     virtual void SAL_CALL disposing( const lang::EventObject& Source )
165         throw( uno::RuntimeException );
166 
167 private:
168     void setNoProxyList( const rtl::OUString & rNoProxyList );
169 };
170 
171 //=========================================================================
172 //=========================================================================
173 //
174 // WildCard Implementation.
175 //
176 //=========================================================================
177 //=========================================================================
178 
Matches(const rtl::OUString & rString) const179 bool WildCard::Matches( const rtl::OUString& rString ) const
180 {
181     rtl::OString aString
182         = rtl::OUStringToOString(
183                     rString, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
184     const char * pStr  = aString.getStr();
185     const char * pWild = m_aWildString.getStr();
186 
187     int pos  = 0;
188     int flag = 0;
189 
190     while ( *pWild || flag )
191     {
192         switch ( *pWild )
193         {
194             case '?':
195                 if ( *pStr == '\0' )
196                     return 0;
197                 break;
198 
199             default:
200                 if ( ( *pWild == '\\' ) && ( ( *( pWild + 1 ) == '?' )
201                                              || ( *( pWild + 1 ) == '*') ) )
202                     pWild++;
203                 if ( *pWild != *pStr )
204                     if ( !pos )
205                         return 0;
206                     else
207                         pWild += pos;
208                 else
209                     break;
210 
211                 // Note: fall-thru's are intended!
212 
213             case '*':
214                 while ( *pWild == '*' )
215                     pWild++;
216                 if ( *pWild == '\0' )
217                     return 1;
218                 flag = 1;
219                 pos  = 0;
220                 if ( *pStr == '\0' )
221                     return ( *pWild == '\0' );
222                 while ( *pStr && *pStr != *pWild )
223                 {
224                     if ( *pWild == '?' ) {
225                         pWild++;
226                         while ( *pWild == '*' )
227                             pWild++;
228                     }
229                     pStr++;
230                     if ( *pStr == '\0' )
231                         return ( *pWild == '\0' );
232                 }
233                 break;
234         }
235         if ( *pWild != '\0' )
236             pWild++;
237         if ( *pStr != '\0' )
238             pStr++;
239         else
240             flag = 0;
241         if ( flag )
242             pos--;
243     }
244     return ( *pStr == '\0' ) && ( *pWild == '\0' );
245 }
246 
247 //=========================================================================
getConfigStringValue(const uno::Reference<container::XNameAccess> & xNameAccess,const char * key,rtl::OUString & value)248 bool getConfigStringValue(
249     const uno::Reference< container::XNameAccess > & xNameAccess,
250     const char * key,
251     rtl::OUString & value )
252 {
253     try
254     {
255         if ( !( xNameAccess->getByName( rtl::OUString::createFromAscii( key ) )
256                 >>= value ) )
257         {
258             OSL_ENSURE( sal_False,
259                         "InternetProxyDecider - "
260                         "Error getting config item value!" );
261             return false;
262         }
263     }
264     catch ( lang::WrappedTargetException const & )
265     {
266         return false;
267     }
268     catch ( container::NoSuchElementException const & )
269     {
270         return false;
271     }
272     return true;
273 }
274 
275 //=========================================================================
getConfigInt32Value(const uno::Reference<container::XNameAccess> & xNameAccess,const char * key,sal_Int32 & value)276 bool getConfigInt32Value(
277     const uno::Reference< container::XNameAccess > & xNameAccess,
278     const char * key,
279     sal_Int32 & value )
280 {
281     try
282     {
283         uno::Any aValue = xNameAccess->getByName(
284             rtl::OUString::createFromAscii( key ) );
285         if ( aValue.hasValue() && !( aValue >>= value ) )
286         {
287             OSL_ENSURE( sal_False,
288                         "InternetProxyDecider - "
289                         "Error getting config item value!" );
290             return false;
291         }
292     }
293     catch ( lang::WrappedTargetException const & )
294     {
295         return false;
296     }
297     catch ( container::NoSuchElementException const & )
298     {
299         return false;
300     }
301     return true;
302 }
303 
304 //=========================================================================
305 //=========================================================================
306 //
307 // InternetProxyDecider_Impl Implementation.
308 //
309 //=========================================================================
310 //=========================================================================
311 
InternetProxyDecider_Impl(const uno::Reference<lang::XMultiServiceFactory> & rxSMgr)312 InternetProxyDecider_Impl::InternetProxyDecider_Impl(
313     const uno::Reference< lang::XMultiServiceFactory >& rxSMgr )
314     : m_nProxyType( 0 ),
315       m_aHostnames( 256 ) // cache size
316 {
317     try
318     {
319         //////////////////////////////////////////////////////////////
320         // Read proxy configuration from config db.
321         //////////////////////////////////////////////////////////////
322 
323         uno::Reference< lang::XMultiServiceFactory > xConfigProv(
324                 rxSMgr->createInstance(
325                     rtl::OUString::createFromAscii(
326                         "com.sun.star.configuration.ConfigurationProvider" ) ),
327                 uno::UNO_QUERY );
328 
329         uno::Sequence< uno::Any > aArguments( 1 );
330         aArguments[ 0 ] <<= rtl::OUString::createFromAscii( CONFIG_ROOT_KEY );
331 
332         uno::Reference< uno::XInterface > xInterface(
333                     xConfigProv->createInstanceWithArguments(
334                         rtl::OUString::createFromAscii(
335                             "com.sun.star.configuration.ConfigurationAccess" ),
336                     aArguments ) );
337 
338         OSL_ENSURE( xInterface.is(),
339                     "InternetProxyDecider - No config access!" );
340 
341         if ( xInterface.is() )
342         {
343             uno::Reference< container::XNameAccess > xNameAccess(
344                                             xInterface, uno::UNO_QUERY );
345             OSL_ENSURE( xNameAccess.is(),
346                         "InternetProxyDecider - No name access!" );
347 
348             if ( xNameAccess.is() )
349             {
350                 // *** Proxy type ***
351                 getConfigInt32Value(
352                     xNameAccess, PROXY_TYPE_KEY, m_nProxyType );
353 
354                 // *** No proxy list ***
355                 rtl::OUString aNoProxyList;
356                 getConfigStringValue(
357                     xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList );
358                 setNoProxyList( aNoProxyList );
359 
360                 // *** HTTP ***
361                 getConfigStringValue(
362                     xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName );
363 
364                 m_aHttpProxy.nPort = -1;
365                 getConfigInt32Value(
366                     xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort );
367                 if ( m_aHttpProxy.nPort == -1 )
368                     m_aHttpProxy.nPort = 80; // standard HTTP port.
369 
370                 // *** HTTPS ***
371                 getConfigStringValue(
372                     xNameAccess, HTTPS_PROXY_NAME_KEY, m_aHttpsProxy.aName );
373 
374                 m_aHttpsProxy.nPort = -1;
375                 getConfigInt32Value(
376                     xNameAccess, HTTPS_PROXY_PORT_KEY, m_aHttpsProxy.nPort );
377                 if ( m_aHttpsProxy.nPort == -1 )
378                     m_aHttpsProxy.nPort = 443; // standard HTTPS port.
379 
380                 // *** FTP ***
381                 getConfigStringValue(
382                     xNameAccess, FTP_PROXY_NAME_KEY, m_aFtpProxy.aName );
383 
384                 m_aFtpProxy.nPort = -1;
385                 getConfigInt32Value(
386                     xNameAccess, FTP_PROXY_PORT_KEY, m_aFtpProxy.nPort );
387             }
388 
389             // Register as listener for config changes.
390 
391             m_xNotifier = uno::Reference< util::XChangesNotifier >(
392                                                 xInterface, uno::UNO_QUERY );
393 
394             OSL_ENSURE( m_xNotifier.is(),
395                         "InternetProxyDecider - No notifier!" );
396 
397             if ( m_xNotifier.is() )
398                 m_xNotifier->addChangesListener( this );
399         }
400     }
401     catch ( uno::Exception const & )
402     {
403         // createInstance, createInstanceWithArguments
404         OSL_ENSURE( sal_False, "InternetProxyDecider - Exception!" );
405     }
406 }
407 
408 //=========================================================================
409 // virtual
~InternetProxyDecider_Impl()410 InternetProxyDecider_Impl::~InternetProxyDecider_Impl()
411 {
412 }
413 
414 //=========================================================================
dispose()415 void InternetProxyDecider_Impl::dispose()
416 {
417     uno::Reference< util::XChangesNotifier > xNotifier;
418 
419     if ( m_xNotifier.is() )
420     {
421         osl::Guard< osl::Mutex > aGuard( m_aMutex );
422 
423         if ( m_xNotifier.is() )
424         {
425             xNotifier = m_xNotifier;
426             m_xNotifier.clear();
427         }
428     }
429 
430     // Do this unguarded!
431     if ( xNotifier.is() )
432         xNotifier->removeChangesListener( this );
433 }
434 
435 //=========================================================================
shouldUseProxy(const rtl::OUString & rHost,sal_Int32 nPort,bool bUseFullyQualified) const436 bool InternetProxyDecider_Impl::shouldUseProxy( const rtl::OUString & rHost,
437                                                 sal_Int32 nPort,
438                                                 bool bUseFullyQualified ) const
439 {
440     rtl::OUStringBuffer aBuffer;
441 
442     if ( ( rHost.indexOf( ':' ) != -1 ) &&
443          ( rHost[ 0 ] != sal_Unicode( '[' ) ) )
444     {
445         // host is given as numeric IPv6 address
446         aBuffer.appendAscii( "[" );
447         aBuffer.append( rHost );
448         aBuffer.appendAscii( "]" );
449     }
450     else
451     {
452         // host is given either as numeric IPv4 address or non-numeric hostname
453         aBuffer.append( rHost );
454     }
455 
456     aBuffer.append( sal_Unicode( ':' ) );
457     aBuffer.append( rtl::OUString::valueOf( nPort ) );
458     const rtl::OUString aHostAndPort( aBuffer.makeStringAndClear() );
459 
460     std::vector< NoProxyListEntry >::const_iterator it
461         = m_aNoProxyList.begin();
462     const std::vector< NoProxyListEntry >::const_iterator end
463         = m_aNoProxyList.end();
464 
465     while ( it != end )
466     {
467         if ( bUseFullyQualified )
468         {
469             if ( (*it).second.Matches( aHostAndPort ) )
470                 return false;
471         }
472         else
473         {
474             if ( (*it).first.Matches( aHostAndPort ) )
475                 return false;
476         }
477         it++;
478     }
479 
480     return true;
481 }
482 
483 //=========================================================================
getProxy(const rtl::OUString & rProtocol,const rtl::OUString & rHost,sal_Int32 nPort) const484 const InternetProxyServer & InternetProxyDecider_Impl::getProxy(
485                                             const rtl::OUString & rProtocol,
486                                             const rtl::OUString & rHost,
487                                             sal_Int32 nPort ) const
488 {
489     osl::Guard< osl::Mutex > aGuard( m_aMutex );
490 
491     if ( m_nProxyType == 0 )
492     {
493         // Never use proxy.
494         return m_aEmptyProxy;
495     }
496 
497     if ( rHost.getLength() && m_aNoProxyList.size() )
498     {
499         //////////////////////////////////////////////////////////////////
500         // First, try direct hostname match - #110515#
501         //////////////////////////////////////////////////////////////////
502 
503         if ( !shouldUseProxy( rHost, nPort, false ) )
504             return m_aEmptyProxy;
505 
506         //////////////////////////////////////////////////////////////////
507         // Second, try match against full qualified hostname - #104401#
508         //////////////////////////////////////////////////////////////////
509 
510         rtl::OUString aHost;
511 
512         if ( ( rHost[ 0 ] == sal_Unicode( '[' ) ) &&
513              ( rHost.getLength() > 1 ) )
514         {
515             // host is given as numeric IPv6 address. name resolution
516             // functions need hostname without square brackets.
517             aHost = rHost.copy( 1, rHost.getLength() - 2 );
518         }
519         else
520         {
521             aHost = rHost;
522         }
523 
524         rtl::OUString aFullyQualifiedHost;
525         if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) )
526         {
527             // This might be quite expensive (DNS lookup).
528             const osl::SocketAddr aAddr( aHost, nPort );
529             aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
530             m_aHostnames.put( aHost, aFullyQualifiedHost );
531         }
532 
533         // Error resolving name? -> fallback.
534         if ( !aFullyQualifiedHost.getLength() )
535             aFullyQualifiedHost = aHost;
536 
537         if ( aFullyQualifiedHost != aHost )
538         {
539             if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) )
540                 return m_aEmptyProxy;
541         }
542 
543         //////////////////////////////////////////////////////////////////
544         // Third, try match of fully qualified entries in no-proxy list
545         // against full qualified hostname
546         //
547         // Example:
548         // list: staroffice-doc -> full: xyz.germany.sun.com
549         // in:   staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com
550         //
551         //////////////////////////////////////////////////////////////////
552 
553         if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) )
554             return m_aEmptyProxy;
555     }
556 
557     if ( rProtocol.toAsciiLowerCase()
558             .equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ftp" ) ) )
559     {
560         if ( m_aFtpProxy.aName.getLength() > 0 && m_aFtpProxy.nPort >= 0 )
561             return m_aFtpProxy;
562     }
563     else if ( rProtocol.toAsciiLowerCase()
564                   .equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) )
565     {
566         if ( m_aHttpsProxy.aName.getLength() )
567             return m_aHttpsProxy;
568     }
569     else if ( m_aHttpProxy.aName.getLength() )
570     {
571         // All other protocols use the HTTP proxy.
572         return m_aHttpProxy;
573     }
574     return m_aEmptyProxy;
575 }
576 
577 //=========================================================================
578 // virtual
changesOccurred(const util::ChangesEvent & Event)579 void SAL_CALL InternetProxyDecider_Impl::changesOccurred(
580                                         const util::ChangesEvent& Event )
581     throw( uno::RuntimeException )
582 {
583     osl::Guard< osl::Mutex > aGuard( m_aMutex );
584 
585     sal_Int32 nCount = Event.Changes.getLength();
586     if ( nCount )
587     {
588         const util::ElementChange* pElementChanges
589             = Event.Changes.getConstArray();
590         for ( sal_Int32 n = 0; n < nCount; ++n )
591         {
592             const util::ElementChange& rElem = pElementChanges[ n ];
593             rtl::OUString aKey;
594             if ( ( rElem.Accessor >>= aKey ) && aKey.getLength() )
595             {
596                 if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
597                                                     PROXY_TYPE_KEY ) ) )
598                 {
599                     if ( !( rElem.Element >>= m_nProxyType ) )
600                     {
601                         OSL_ENSURE( sal_False,
602                                     "InternetProxyDecider - changesOccurred - "
603                                     "Error getting config item value!" );
604                     }
605                 }
606                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
607                                                     NO_PROXY_LIST_KEY ) ) )
608                 {
609                     rtl::OUString aNoProxyList;
610                     if ( !( rElem.Element >>= aNoProxyList ) )
611                     {
612                         OSL_ENSURE( sal_False,
613                                     "InternetProxyDecider - changesOccurred - "
614                                     "Error getting config item value!" );
615                     }
616 
617                     setNoProxyList( aNoProxyList );
618                 }
619                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
620                                                     HTTP_PROXY_NAME_KEY ) ) )
621                 {
622                     if ( !( rElem.Element >>= m_aHttpProxy.aName ) )
623                     {
624                         OSL_ENSURE( sal_False,
625                                     "InternetProxyDecider - changesOccurred - "
626                                     "Error getting config item value!" );
627                     }
628                 }
629                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
630                                                     HTTP_PROXY_PORT_KEY ) ) )
631                 {
632                     if ( !( rElem.Element >>= m_aHttpProxy.nPort ) )
633                     {
634                         OSL_ENSURE( sal_False,
635                                     "InternetProxyDecider - changesOccurred - "
636                                     "Error getting config item value!" );
637                     }
638 
639                     if ( m_aHttpProxy.nPort == -1 )
640                         m_aHttpProxy.nPort = 80; // standard HTTP port.
641                 }
642                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
643                                                     HTTPS_PROXY_NAME_KEY ) ) )
644                 {
645                     if ( !( rElem.Element >>= m_aHttpsProxy.aName ) )
646                     {
647                         OSL_ENSURE( sal_False,
648                                     "InternetProxyDecider - changesOccurred - "
649                                     "Error getting config item value!" );
650                     }
651                 }
652                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
653                                                     HTTPS_PROXY_PORT_KEY ) ) )
654                 {
655                     if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) )
656                     {
657                         OSL_ENSURE( sal_False,
658                                     "InternetProxyDecider - changesOccurred - "
659                                     "Error getting config item value!" );
660                     }
661 
662                     if ( m_aHttpsProxy.nPort == -1 )
663                         m_aHttpsProxy.nPort = 443; // standard HTTPS port.
664                 }
665                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
666                                                     FTP_PROXY_NAME_KEY ) ) )
667                 {
668                     if ( !( rElem.Element >>= m_aFtpProxy.aName ) )
669                     {
670                         OSL_ENSURE( sal_False,
671                                     "InternetProxyDecider - changesOccurred - "
672                                     "Error getting config item value!" );
673                     }
674                 }
675                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
676                                                     FTP_PROXY_PORT_KEY ) ) )
677                 {
678                     if ( !( rElem.Element >>= m_aFtpProxy.nPort ) )
679                     {
680                         OSL_ENSURE( sal_False,
681                                     "InternetProxyDecider - changesOccurred - "
682                                     "Error getting config item value!" );
683                     }
684                 }
685             }
686         }
687     }
688 }
689 
690 //=========================================================================
691 // virtual
disposing(const lang::EventObject &)692 void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&)
693     throw( uno::RuntimeException )
694 {
695     if ( m_xNotifier.is() )
696     {
697         osl::Guard< osl::Mutex > aGuard( m_aMutex );
698 
699         if ( m_xNotifier.is() )
700             m_xNotifier.clear();
701     }
702 }
703 
704 //=========================================================================
setNoProxyList(const rtl::OUString & rNoProxyList)705 void InternetProxyDecider_Impl::setNoProxyList(
706                                         const rtl::OUString & rNoProxyList )
707 {
708     osl::Guard< osl::Mutex > aGuard( m_aMutex );
709 
710     m_aNoProxyList.clear();
711 
712     if ( rNoProxyList.getLength() )
713     {
714         // List of connection endpoints hostname[:port],
715         // separated by semicolon. Wilcards allowed.
716 
717         sal_Int32 nPos = 0;
718         sal_Int32 nEnd = rNoProxyList.indexOf( ';' );
719         sal_Int32 nLen = rNoProxyList.getLength();
720 
721         do
722         {
723             if ( nEnd == -1 )
724                 nEnd = nLen;
725 
726             rtl::OUString aToken = rNoProxyList.copy( nPos, nEnd - nPos );
727 
728             if ( aToken.getLength() )
729             {
730                 rtl::OUString aServer;
731                 rtl::OUString aPort;
732 
733                 // numerical IPv6 address?
734                 bool bIPv6Address = false;
735                 sal_Int32 nClosedBracketPos = aToken.indexOf( ']' );
736                 if ( nClosedBracketPos == -1 )
737                     nClosedBracketPos = 0;
738                 else
739                     bIPv6Address = true;
740 
741                 sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos );
742                 if ( nColonPos == -1 )
743                 {
744                     // No port given, server pattern equals current token
745                     aPort = rtl::OUString::createFromAscii( "*" );
746                     if ( aToken.indexOf( '*' ) == -1 )
747                     {
748                         // pattern describes exactly one server
749                         aServer = aToken;
750                     }
751 
752                     aToken += rtl::OUString::createFromAscii( ":*" );
753                 }
754                 else
755                 {
756                     // Port given, extract server pattern
757                     sal_Int32 nAsterixPos = aToken.indexOf( '*' );
758                     aPort = aToken.copy( nColonPos + 1 );
759                     if ( nAsterixPos < nColonPos )
760                     {
761                         // pattern describes exactly one server
762                         aServer = aToken.copy( 0, nColonPos );
763                     }
764                 }
765 
766                 rtl::OUStringBuffer aFullyQualifiedHost;
767                 if ( aServer.getLength() )
768                 {
769                     // Remember fully qualified server name if current list
770                     // entry specifies exactly one non-fully qualified server
771                     // name.
772 
773                     // remove square brackets from host name in case it's
774                     // a numerical IPv6 address.
775                     if ( bIPv6Address )
776                         aServer = aServer.copy( 1, aServer.getLength() - 2 );
777 
778                     // This might be quite expensive (DNS lookup).
779                     const osl::SocketAddr aAddr( aServer, 0 );
780                     rtl::OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
781                     if ( aTmp != aServer.toAsciiLowerCase() )
782                     {
783                         if ( bIPv6Address )
784                         {
785                             aFullyQualifiedHost.appendAscii( "[" );
786                             aFullyQualifiedHost.append( aTmp );
787                             aFullyQualifiedHost.appendAscii( "]" );
788                         }
789                         else
790                         {
791                             aFullyQualifiedHost.append( aTmp );
792                         }
793                         aFullyQualifiedHost.appendAscii( ":" );
794                         aFullyQualifiedHost.append( aPort );
795                     }
796                 }
797 
798                 m_aNoProxyList.push_back(
799                     NoProxyListEntry( WildCard( aToken ),
800                                       WildCard(
801                                         aFullyQualifiedHost
802                                             .makeStringAndClear() ) ) );
803             }
804 
805             if ( nEnd != nLen )
806             {
807                 nPos = nEnd + 1;
808                 nEnd = rNoProxyList.indexOf( ';', nPos );
809             }
810         }
811         while ( nEnd != nLen );
812     }
813 }
814 
815 } // namespace proxydecider_impl
816 
817 //=========================================================================
818 //=========================================================================
819 //
820 // InternetProxyDecider Implementation.
821 //
822 //=========================================================================
823 //=========================================================================
824 
InternetProxyDecider(const uno::Reference<lang::XMultiServiceFactory> & rxSMgr)825 InternetProxyDecider::InternetProxyDecider(
826     const uno::Reference< lang::XMultiServiceFactory >& rxSMgr )
827 : m_pImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxSMgr ) )
828 {
829     m_pImpl->acquire();
830 }
831 
832 //=========================================================================
~InternetProxyDecider()833 InternetProxyDecider::~InternetProxyDecider()
834 {
835     // Break circular reference between config listener and notifier.
836     m_pImpl->dispose();
837 
838     // Let him go...
839     m_pImpl->release();
840 }
841 
842 //=========================================================================
shouldUseProxy(const rtl::OUString & rProtocol,const rtl::OUString & rHost,sal_Int32 nPort) const843 bool InternetProxyDecider::shouldUseProxy( const rtl::OUString & rProtocol,
844                                            const rtl::OUString & rHost,
845                                            sal_Int32 nPort ) const
846 {
847     const InternetProxyServer & rData = m_pImpl->getProxy( rProtocol,
848                                                            rHost,
849                                                            nPort );
850     return ( rData.aName.getLength() > 0 );
851 }
852 
853 //=========================================================================
getProxy(const rtl::OUString & rProtocol,const rtl::OUString & rHost,sal_Int32 nPort) const854 const InternetProxyServer & InternetProxyDecider::getProxy(
855                                             const rtl::OUString & rProtocol,
856                                             const rtl::OUString & rHost,
857                                             sal_Int32 nPort ) const
858 {
859     return m_pImpl->getProxy( rProtocol, rHost, nPort );
860 }
861 
862 } // namespace ucbhelper
863